Upgrade to OpenSSH 5.4p1.

MFC after:	1 month
This commit is contained in:
Dag-Erling Smørgrav 2010-03-09 19:16:43 +00:00
commit b15c83408c
129 changed files with 10924 additions and 3046 deletions

View File

@ -1,3 +1,982 @@
20100307
- (djm) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/03/07 22:16:01
[ssh-keygen.c]
make internal strptime string match strftime format;
suggested by vinschen AT redhat.com and markus@
- djm@cvs.openbsd.org 2010/03/08 00:28:55
[ssh-keygen.1]
document permit-agent-forwarding certificate constraint; patch from
stevesk@
- djm@cvs.openbsd.org 2010/03/07 22:01:32
[version.h]
openssh-5.4
- (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
crank version numbers
- (djm) Release OpenSSH-5.4p1
20100307
- (dtucker) [auth.c] Bug #1710: call setauthdb on AIX before getpwuid so that
it gets the passwd struct from the LAM that knows about the user which is
not necessarily the default. Patch from Alexandre Letourneau.
- (dtucker) [session.c] Bug #1567: move setpcred call to before chroot and
do not set real uid, since that's needed for the chroot, and will be set
by permanently_set_uid.
- (dtucker) [session.c] Also initialize creds to NULL for handing to
setpcred.
- (dtucker) OpenBSD CVS Sync
- dtucker@cvs.openbsd.org 2010/03/07 11:57:13
[auth-rhosts.c monitor.c monitor_wrap.c session.c auth-options.c sshd.c]
Hold authentication debug messages until after successful authentication.
Fixes an info leak of environment variables specified in authorized_keys,
reported by Jacob Appelbaum. ok djm@
20100305
- OpenBSD CVS Sync
- jmc@cvs.openbsd.org 2010/03/04 12:51:25
[ssh.1 sshd_config.5]
tweak previous;
- djm@cvs.openbsd.org 2010/03/04 20:35:08
[ssh-keygen.1 ssh-keygen.c]
Add a -L flag to print the contents of a certificate; ok markus@
- jmc@cvs.openbsd.org 2010/03/04 22:52:40
[ssh-keygen.1]
fix Bk/Ek;
- djm@cvs.openbsd.org 2010/03/04 23:17:25
[sshd_config.5]
missing word; spotted by jmc@
- djm@cvs.openbsd.org 2010/03/04 23:19:29
[ssh.1 sshd.8]
move section on CA and revoked keys from ssh.1 to sshd.8's known hosts
format section and rework it a bit; requested by jmc@
- djm@cvs.openbsd.org 2010/03/04 23:27:25
[auth-options.c ssh-keygen.c]
"force-command" is not spelled "forced-command"; spotted by
imorgan AT nas.nasa.gov
- djm@cvs.openbsd.org 2010/03/05 02:58:11
[auth.c]
make the warning for a revoked key louder and more noticable
- jmc@cvs.openbsd.org 2010/03/05 06:50:35
[ssh.1 sshd.8]
tweak previous;
- jmc@cvs.openbsd.org 2010/03/05 08:31:20
[ssh.1]
document certificate authentication; help/ok djm
- djm@cvs.openbsd.org 2010/03/05 10:28:21
[ssh-add.1 ssh.1 ssh_config.5]
mention loading of certificate files from [private]-cert.pub when
they are present; feedback and ok jmc@
- (tim) [ssh-pkcs11.c] Fix "non-constant initializer" errors in older
compilers. OK djm@
- (djm) [ssh-rand-helper.c] declare optind, avoiding compilation failure
on some platforms
- (djm) [configure.ac] set -fno-strict-aliasing for gcc4; ok dtucker@
20100304
- (djm) [ssh-keygen.c] Use correct local variable, instead of
maybe-undefined global "optarg"
- (djm) [contrib/redhat/openssh.spec] Replace obsolete BuildPreReq
on XFree86-devel with neutral /usr/include/X11/Xlib.h;
imorgan AT nas.nasa.gov in bz#1731
- (djm) [.cvsignore] Ignore ssh-pkcs11-helper
- (djm) [regress/Makefile] Cleanup sshd_proxy_orig
- OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/03/03 01:44:36
[auth-options.c key.c]
reject strings with embedded ASCII nul chars in certificate key IDs,
principal names and constraints
- djm@cvs.openbsd.org 2010/03/03 22:49:50
[sshd.8]
the authorized_keys option for CA keys is "cert-authority", not
"from=cert-authority". spotted by imorgan AT nas.nasa.gov
- djm@cvs.openbsd.org 2010/03/03 22:50:40
[PROTOCOL.certkeys]
s/similar same/similar/; from imorgan AT nas.nasa.gov
- djm@cvs.openbsd.org 2010/03/04 01:44:57
[key.c]
use buffer_get_string_ptr_ret() where we are checking the return
value explicitly instead of the fatal()-causing buffer_get_string_ptr()
- djm@cvs.openbsd.org 2010/03/04 10:36:03
[auth-rh-rsa.c auth-rsa.c auth.c auth.h auth2-hostbased.c auth2-pubkey.c]
[authfile.c authfile.h hostfile.c hostfile.h servconf.c servconf.h]
[ssh-keygen.c ssh.1 sshconnect.c sshd_config.5]
Add a TrustedUserCAKeys option to sshd_config to specify CA keys that
are trusted to authenticate users (in addition than doing it per-user
in authorized_keys).
Add a RevokedKeys option to sshd_config and a @revoked marker to
known_hosts to allow keys to me revoked and banned for user or host
authentication.
feedback and ok markus@
- djm@cvs.openbsd.org 2010/03/03 00:47:23
[regress/cert-hostkey.sh regress/cert-userkey.sh]
add an extra test to ensure that authentication with the wrong
certificate fails as it should (and it does)
- djm@cvs.openbsd.org 2010/03/04 10:38:23
[regress/cert-hostkey.sh regress/cert-userkey.sh]
additional regression tests for revoked keys and TrustedUserCAKeys
20100303
- (djm) [PROTOCOL.certkeys] Add RCS Ident
- OpenBSD CVS Sync
- jmc@cvs.openbsd.org 2010/02/26 22:09:28
[ssh-keygen.1 ssh.1 sshd.8]
tweak previous;
- otto@cvs.openbsd.org 2010/03/01 11:07:06
[ssh-add.c]
zap what seems to be a left-over debug message; ok markus@
- djm@cvs.openbsd.org 2010/03/02 23:20:57
[ssh-keygen.c]
POSIX strptime is stricter than OpenBSD's so do a little dance to
appease it.
- (djm) [regress/cert-userkey.sh] s/echo -n/echon/ here too
20100302
- (tim) [config.guess config.sub] Bug 1722: Update to latest versions from
http://git.savannah.gnu.org/gitweb/ (2009-12-30 and 2010-01-22
respectively).
20100301
- (dtucker) [regress/{cert-hostkey,cfgmatch,cipher-speed}.sh} Replace
"echo -n" with "echon" for portability.
- (dtucker) [openbsd-compat/port-linux.c] Make failure to write to the OOM
adjust log at verbose only, since according to cjwatson in bug #1470
some virtualization platforms don't allow writes.
20100228
- (djm) [auth.c] On Cygwin, refuse usernames that have differences in
case from that matched in the system password database. On this
platform, passwords are stored case-insensitively, but sshd requires
exact case matching for Match blocks in sshd_config(5). Based on
a patch from vinschen AT redhat.com.
- (tim) [ssh-pkcs11-helper.c] Move declarations before calling functions
to make older compilers (gcc 2.95) happy.
20100227
- (djm) [ssh-pkcs11-helper.c ] Ensure RNG is initialised and seeded
- (djm) [openbsd-compat/bsd-cygwin_util.c] Reduce the set of environment
variables copied into sshd child processes. From vinschen AT redhat.com
20100226
- OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/02/26 20:29:54
[PROTOCOL PROTOCOL.agent PROTOCOL.certkeys addrmatch.c auth-options.c]
[auth-options.h auth.h auth2-pubkey.c authfd.c dns.c dns.h hostfile.c]
[hostfile.h kex.h kexdhs.c kexgexs.c key.c key.h match.h monitor.c]
[myproposal.h servconf.c servconf.h ssh-add.c ssh-agent.c ssh-dss.c]
[ssh-keygen.1 ssh-keygen.c ssh-rsa.c ssh.1 ssh.c ssh2.h sshconnect.c]
[sshconnect2.c sshd.8 sshd.c sshd_config.5]
Add support for certificate key types for users and hosts.
OpenSSH certificate key types are not X.509 certificates, but a much
simpler format that encodes a public key, identity information and
some validity constraints and signs it with a CA key. CA keys are
regular SSH keys. This certificate style avoids the attack surface
of X.509 certificates and is very easy to deploy.
Certified host keys allow automatic acceptance of new host keys
when a CA certificate is marked as trusted in ~/.ssh/known_hosts.
see VERIFYING HOST KEYS in ssh(1) for details.
Certified user keys allow authentication of users when the signing
CA key is marked as trusted in authorized_keys. See "AUTHORIZED_KEYS
FILE FORMAT" in sshd(8) for details.
Certificates are minted using ssh-keygen(1), documentation is in
the "CERTIFICATES" section of that manpage.
Documentation on the format of certificates is in the file
PROTOCOL.certkeys
feedback and ok markus@
- djm@cvs.openbsd.org 2010/02/26 20:33:21
[Makefile regress/cert-hostkey.sh regress/cert-userkey.sh]
regression tests for certified keys
20100224
- (djm) [pkcs11.h ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c]
[ssh-pkcs11.h] Add $OpenBSD$ RCS idents so we can sync portable
- (djm) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/02/11 20:37:47
[pathnames.h]
correct comment
- dtucker@cvs.openbsd.org 2009/11/09 04:20:04
[regress/Makefile]
add regression test for ssh-keygen pubkey conversions
- dtucker@cvs.openbsd.org 2010/01/11 02:53:44
[regress/forwarding.sh]
regress test for stdio forwarding
- djm@cvs.openbsd.org 2010/02/09 04:57:36
[regress/addrmatch.sh]
clean up droppings
- djm@cvs.openbsd.org 2010/02/09 06:29:02
[regress/Makefile]
turn on all the malloc(3) checking options when running regression
tests. this has caught a few bugs for me in the past; ok dtucker@
- djm@cvs.openbsd.org 2010/02/24 06:21:56
[regress/test-exec.sh]
wait for sshd to fully stop in cleanup() function; avoids races in tests
that do multiple start_sshd/cleanup cycles; "I hate pidfiles" deraadt@
- markus@cvs.openbsd.org 2010/02/08 10:52:47
[regress/agent-pkcs11.sh]
test for PKCS#11 support (currently disabled)
- (djm) [Makefile.in ssh-pkcs11-helper.8] Add manpage for PKCS#11 helper
- (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
[contrib/suse/openssh.spec] Add PKCS#11 helper binary and manpage
20100212
- (djm) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/02/02 22:49:34
[bufaux.c]
make buffer_get_string_ret() really non-fatal in all cases (it was
using buffer_get_int(), which could fatal() on buffer empty);
ok markus dtucker
- markus@cvs.openbsd.org 2010/02/08 10:50:20
[pathnames.h readconf.c readconf.h scp.1 sftp.1 ssh-add.1 ssh-add.c]
[ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config.5]
replace our obsolete smartcard code with PKCS#11.
ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/pkcs-11v2-20.pdf
ssh(1) and ssh-keygen(1) use dlopen(3) directly to talk to a PKCS#11
provider (shared library) while ssh-agent(1) delegates PKCS#11 to
a forked a ssh-pkcs11-helper process.
PKCS#11 is currently a compile time option.
feedback and ok djm@; inspired by patches from Alon Bar-Lev
- jmc@cvs.openbsd.org 2010/02/08 22:03:05
[ssh-add.1 ssh-keygen.1 ssh.1 ssh.c]
tweak previous; ok markus
- djm@cvs.openbsd.org 2010/02/09 00:50:36
[ssh-agent.c]
fallout from PKCS#11: unbreak -D
- djm@cvs.openbsd.org 2010/02/09 00:50:59
[ssh-keygen.c]
fix -Wall
- djm@cvs.openbsd.org 2010/02/09 03:56:28
[buffer.c buffer.h]
constify the arguments to buffer_len, buffer_ptr and buffer_dump
- djm@cvs.openbsd.org 2010/02/09 06:18:46
[auth.c]
unbreak ChrootDirectory+internal-sftp by skipping check for executable
shell when chrooting; reported by danh AT wzrd.com; ok dtucker@
- markus@cvs.openbsd.org 2010/02/10 23:20:38
[ssh-add.1 ssh-keygen.1 ssh.1 ssh_config.5]
pkcs#11 is no longer optional; improve wording; ok jmc@
- jmc@cvs.openbsd.org 2010/02/11 13:23:29
[ssh.1]
libarary -> library;
- (djm) [INSTALL Makefile.in README.smartcard configure.ac scard-opensc.c]
[scard.c scard.h pkcs11.h scard/Makefile.in scard/Ssh.bin.uu scard/Ssh.java]
Remove obsolete smartcard support
- (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c]
Make it compile on OSX
- (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c]
Use ssh_get_progname to fill __progname
- (djm) [configure.ac] Enable PKCS#11 support only when we find a working
dlopen()
20100210
- (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for
getseuserbyname; patch from calebcase AT gmail.com via
cjwatson AT debian.org
20100202
- (djm) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/01/30 21:08:33
[sshd.8]
debug output goes to stderr, not "the system log"; ok markus dtucker
- djm@cvs.openbsd.org 2010/01/30 21:12:08
[channels.c]
fake local addr:port when stdio fowarding as some servers (Tectia at
least) validate that they are well-formed;
reported by imorgan AT nas.nasa.gov
ok dtucker
20100130
- (djm) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/01/28 00:21:18
[clientloop.c]
downgrade an error() to a debug() - this particular case can be hit in
normal operation for certain sequences of mux slave vs session closure
and is harmless
- djm@cvs.openbsd.org 2010/01/29 00:20:41
[sshd.c]
set FD_CLOEXEC on sock_in/sock_out; bz#1706 from jchadima AT redhat.com
ok dtucker@
- djm@cvs.openbsd.org 2010/01/29 20:16:17
[mux.c]
kill correct channel (was killing already-dead mux channel, not
its session channel)
- djm@cvs.openbsd.org 2010/01/30 02:54:53
[mux.c]
don't mark channel as read failed if it is already closing; suppresses
harmless error messages when connecting to SSH.COM Tectia server
report by imorgan AT nas.nasa.gov
20100129
- (dtucker) [openbsd-compat/openssl-compat.c] Bug #1707: Call OPENSSL_config()
after registering the hardware engines, which causes the openssl.cnf file to
be processed. See OpenSSL's man page for OPENSSL_config(3) for details.
Patch from Solomon Peachy, ok djm@.
20100128
- (djm) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/01/26 02:15:20
[mux.c]
-Wuninitialized and remove a // comment; from portable
(Id sync only)
- djm@cvs.openbsd.org 2010/01/27 13:26:17
[mux.c]
fix bug introduced in mux rewrite:
In a mux master, when a socket to a mux slave closes before its server
session (as may occur when the slave has been signalled), gracefully
close the server session rather than deleting its channel immediately.
A server may have more messages on that channel to send (e.g. an exit
message) that will fatal() the client if they are sent to a channel that
has been prematurely deleted.
spotted by imorgan AT nas.nasa.gov
- djm@cvs.openbsd.org 2010/01/27 19:21:39
[sftp.c]
add missing "p" flag to getopt optstring;
bz#1704 from imorgan AT nas.nasa.gov
20100126
- (djm) OpenBSD CVS Sync
- tedu@cvs.openbsd.org 2010/01/17 21:49:09
[ssh-agent.1]
Correct and clarify ssh-add's password asking behavior.
Improved text dtucker and ok jmc
- dtucker@cvs.openbsd.org 2010/01/18 01:50:27
[roaming_client.c]
s/long long unsigned/unsigned long long/, from tim via portable
(Id sync only, change already in portable)
- djm@cvs.openbsd.org 2010/01/26 01:28:35
[channels.c channels.h clientloop.c clientloop.h mux.c nchan.c ssh.c]
rewrite ssh(1) multiplexing code to a more sensible protocol.
The new multiplexing code uses channels for the listener and
accepted control sockets to make the mux master non-blocking, so
no stalls when processing messages from a slave.
avoid use of fatal() in mux master protocol parsing so an errant slave
process cannot take down a running master.
implement requesting of port-forwards over multiplexed sessions. Any
port forwards requested by the slave are added to those the master has
established.
add support for stdio forwarding ("ssh -W host:port ...") in mux slaves.
document master/slave mux protocol so that other tools can use it to
control a running ssh(1). Note: there are no guarantees that this
protocol won't be incompatibly changed (though it is versioned).
feedback Salvador Fandino, dtucker@
channel changes ok markus@
20100122
- (tim) [configure.ac] Due to constraints in Windows Sockets in terms of
socket inheritance, reduce the default SO_RCVBUF/SO_SNDBUF buffer size
in Cygwin to 65535. Patch from Corinna Vinschen.
20100117
- (tim) [configure.ac] OpenServer 5 needs BROKEN_GETADDRINFO too.
- (tim) [configure.ac] On SVR5 systems, use the C99-conforming functions
snprintf() and vsnprintf() named _xsnprintf() and _xvsnprintf().
20100116
- (dtucker) [openbsd-compat/pwcache.c] Pull in includes.h and thus defines.h
so we correctly detect whether or not we have a native user_from_uid.
- (dtucker) [openbsd-compat/openbsd-compat.h] Prototypes for user_from_uid
and group_from_gid.
- (dtucker) [openbsd-compat/openbsd-compat.h] Fix prototypes, spotted by
Tim.
- (dtucker) OpenBSD CVS Sync
- markus@cvs.openbsd.org 2010/01/15 09:24:23
[sftp-common.c]
unused
- (dtucker) [openbsd-compat/pwcache.c] Shrink ifdef area to prevent unused
variable warnings.
- (dtucker) [openbsd-compat/openbsd-compat.h] Typo.
- (tim) [regress/portnum.sh] Shell portability fix.
- (tim) [configure.ac] Define BROKEN_GETADDRINFO on SVR5 systems. The native
getaddrinfo() is too old and limited for addr_pton() in addrmatch.c.
- (tim) [roaming_client.c] Use of <sys/queue.h> is not really portable so we
use "openbsd-compat/sys-queue.h". s/long long unsigned/unsigned long long/
to keep USL compilers happy.
20100115
- (dtucker) OpenBSD CVS Sync
- jmc@cvs.openbsd.org 2010/01/13 12:48:34
[sftp.1 sftp.c]
sftp.1: put ls -h in the right place
sftp.c: as above, plus add -p to get/put, and shorten their arg names
to keep the help usage nicely aligned
ok djm
- djm@cvs.openbsd.org 2010/01/13 23:47:26
[auth.c]
when using ChrootDirectory, make sure we test for the existence of the
user's shell inside the chroot; bz #1679, patch from alex AT rtfs.hu;
ok dtucker
- dtucker@cvs.openbsd.org 2010/01/14 23:41:49
[sftp-common.c]
use user_from{uid,gid} to lookup up ids since it keeps a small cache.
ok djm
- guenther@cvs.openbsd.org 2010/01/15 00:05:22
[sftp.c]
Reset SIGTERM to SIG_DFL before executing ssh, so that even if sftp
inherited SIGTERM as ignored it will still be able to kill the ssh it
starts.
ok dtucker@
- (dtucker) [openbsd-compat/pwcache.c] Pull in pwcache.c from OpenBSD (no
changes yet but there will be some to come).
- (dtucker) [configure.ac openbsd-compat/{Makefile.in,pwcache.c} Portability
for pwcache. Also, added caching of negative hits.
20100114
- (djm) [platform.h] Add missing prototype for
platform_krb5_get_principal_name
20100113
- (dtucker) [monitor_fdpass.c] Wrap poll.h include in ifdefs.
- (dtucker) [openbsd-compat/readpassphrase.c] Resync against OpenBSD's r1.18:
missing restore of SIGTTOU and some whitespace.
- (dtucker) [openbsd-compat/readpassphrase.c] Update to OpenBSD's r1.21.
- (dtucker) [openbsd-compat/readpassphrase.c] Update to OpenBSD's r1.22.
Fixes bz #1590, where sometimes you could not interrupt a connection while
ssh was prompting for a passphrase or password.
- (dtucker) OpenBSD CVS Sync
- dtucker@cvs.openbsd.org 2010/01/13 00:19:04
[sshconnect.c auth.c]
Fix a couple of typos/mispellings in comments
- dtucker@cvs.openbsd.org 2010/01/13 01:10:56
[key.c]
Ignore and log any Protocol 1 keys where the claimed size is not equal to
the actual size. Noted by Derek Martin, ok djm@
- dtucker@cvs.openbsd.org 2010/01/13 01:20:20
[canohost.c ssh-keysign.c sshconnect2.c]
Make HostBased authentication work with a ProxyCommand. bz #1569, patch
from imorgan at nas nasa gov, ok djm@
- djm@cvs.openbsd.org 2010/01/13 01:40:16
[sftp.c sftp-server.c sftp.1 sftp-common.c sftp-common.h]
support '-h' (human-readable units) for sftp's ls command, just like
ls(1); ok dtucker@
- djm@cvs.openbsd.org 2010/01/13 03:48:13
[servconf.c servconf.h sshd.c]
avoid run-time failures when specifying hostkeys via a relative
path by prepending the cwd in these cases; bz#1290; ok dtucker@
- djm@cvs.openbsd.org 2010/01/13 04:10:50
[sftp.c]
don't append a space after inserting a completion of a directory (i.e.
a path ending in '/') for a slightly better user experience; ok dtucker@
- (dtucker) [sftp-common.c] Wrap include of util.h in an ifdef.
- (tim) [defines.h] openbsd-compat/readpassphrase.c now needs _NSIG.
feedback and ok dtucker@
20100112
- (dtucker) OpenBSD CVS Sync
- dtucker@cvs.openbsd.org 2010/01/11 01:39:46
[ssh_config channels.c ssh.1 channels.h ssh.c]
Add a 'netcat mode' (ssh -W). This connects stdio on the client to a
single port forward on the server. This allows, for example, using ssh as
a ProxyCommand to route connections via intermediate servers.
bz #1618, man page help from jmc@, ok markus@
- dtucker@cvs.openbsd.org 2010/01/11 04:46:45
[authfile.c sshconnect2.c]
Do not prompt for a passphrase if we fail to open a keyfile, and log the
reason the open failed to debug.
bz #1693, found by tj AT castaglia org, ok djm@
- djm@cvs.openbsd.org 2010/01/11 10:51:07
[ssh-keygen.c]
when converting keys, truncate key comments at 72 chars as per RFC4716;
bz#1630 reported by tj AT castaglia.org; ok markus@
- dtucker@cvs.openbsd.org 2010/01/12 00:16:47
[authfile.c]
Fix bug introduced in r1.78 (incorrect brace location) that broke key auth.
Patch from joachim joachimschipper nl.
- djm@cvs.openbsd.org 2010/01/12 00:58:25
[monitor_fdpass.c]
avoid spinning when fd passing on nonblocking sockets by calling poll()
in the EINTR/EAGAIN path, much like we do in atomicio; ok dtucker@
- djm@cvs.openbsd.org 2010/01/12 00:59:29
[roaming_common.c]
delete with extreme prejudice a debug() that fired with every keypress;
ok dtucker deraadt
- dtucker@cvs.openbsd.org 2010/01/12 01:31:05
[session.c]
Do not allow logins if /etc/nologin exists but is not readable by the user
logging in. Noted by Jan.Pechanec at Sun, ok djm@ deraadt@
- djm@cvs.openbsd.org 2010/01/12 01:36:08
[buffer.h bufaux.c]
add a buffer_get_string_ptr_ret() that does the same as
buffer_get_string_ptr() but does not fatal() on error; ok dtucker@
- dtucker@cvs.openbsd.org 2010/01/12 08:33:17
[session.c]
Add explicit stat so we reliably detect nologin with bad perms.
ok djm markus
20100110
- (dtucker) [configure.ac misc.c readconf.c servconf.c ssh-keyscan.c]
Remove hacks add for RoutingDomain in preparation for its removal.
- (dtucker) OpenBSD CVS Sync
- dtucker@cvs.openbsd.org 2010/01/09 23:04:13
[channels.c ssh.1 servconf.c sshd_config.5 sshd.c channels.h servconf.h
ssh-keyscan.1 ssh-keyscan.c readconf.c sshconnect.c misc.c ssh.c
readconf.h scp.1 sftp.1 ssh_config.5 misc.h]
Remove RoutingDomain from ssh since it's now not needed. It can be
replaced with "route exec" or "nc -V" as a proxycommand. "route exec"
also ensures that trafic such as DNS lookups stays withing the specified
routingdomain. For example (from reyk):
# route -T 2 exec /usr/sbin/sshd
or inherited from the parent process
$ route -T 2 exec sh
$ ssh 10.1.2.3
ok deraadt@ markus@ stevesk@ reyk@
- dtucker@cvs.openbsd.org 2010/01/10 03:51:17
[servconf.c]
Add ChrootDirectory to sshd.c test-mode output
- dtucker@cvs.openbsd.org 2010/01/10 07:15:56
[auth.c]
Output a debug if we can't open an existing keyfile. bz#1694, ok djm@
20100109
- (dtucker) Wrap use of IPPROTO_IPV6 in an ifdef for platforms that don't
have it.
- (dtucker) [defines.h] define PRIu64 for platforms that don't have it.
- (dtucker) [roaming_client.c] Wrap inttypes.h in an ifdef.
- (dtucker) [loginrec.c] Use the SUSv3 specified name for the user name
when using utmpx. Patch from Ed Schouten.
- (dtucker) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2010/01/09 00:20:26
[sftp-server.c sftp-server.8]
add a 'read-only' mode to sftp-server(8) that disables open in write mode
and all other fs-modifying protocol methods. bz#430 ok dtucker@
- djm@cvs.openbsd.org 2010/01/09 00:57:10
[PROTOCOL]
tweak language
- jmc@cvs.openbsd.org 2010/01/09 03:36:00
[sftp-server.8]
bad place to forget a comma...
- djm@cvs.openbsd.org 2010/01/09 05:04:24
[mux.c sshpty.h clientloop.c sshtty.c]
quell tc[gs]etattr warnings when forcing a tty (ssh -tt), since we
usually don't actually have a tty to read/set; bz#1686 ok dtucker@
- dtucker@cvs.openbsd.org 2010/01/09 05:17:00
[roaming_client.c]
Remove a PRIu64 format string that snuck in with roaming. ok djm@
- dtucker@cvs.openbsd.org 2010/01/09 11:13:02
[sftp.c]
Prevent sftp from derefing a null pointer when given a "-" without a
command. Also, allow whitespace to follow a "-". bz#1691, path from
Colin Watson via Debian. ok djm@ deraadt@
- dtucker@cvs.openbsd.org 2010/01/09 11:17:56
[sshd.c]
Afer sshd receives a SIGHUP, ignore subsequent HUPs while sshd re-execs
itself. Prevents two HUPs in quick succession from resulting in sshd
dying. bz#1692, patch from Colin Watson via Ubuntu.
- (dtucker) [defines.h] Remove now-undeeded PRIu64 define.
20100108
- (dtucker) OpenBSD CVS Sync
- andreas@cvs.openbsd.org 2009/10/24 11:11:58
[roaming.h]
Declarations needed for upcoming changes.
ok markus@
- andreas@cvs.openbsd.org 2009/10/24 11:13:54
[sshconnect2.c kex.h kex.c]
Let the client detect if the server supports roaming by looking
for the resume@appgate.com kex algorithm.
ok markus@
- andreas@cvs.openbsd.org 2009/10/24 11:15:29
[clientloop.c]
client_loop() must detect if the session has been suspended and resumed,
and take appropriate action in that case.
From Martin Forssen, maf at appgate dot com
- andreas@cvs.openbsd.org 2009/10/24 11:19:17
[ssh2.h]
Define the KEX messages used when resuming a suspended connection.
ok markus@
- andreas@cvs.openbsd.org 2009/10/24 11:22:37
[roaming_common.c]
Do the actual suspend/resume in the client. This won't be useful until
the server side supports roaming.
Most code from Martin Forssen, maf at appgate dot com. Some changes by
me and markus@
ok markus@
- andreas@cvs.openbsd.org 2009/10/24 11:23:42
[ssh.c]
Request roaming to be enabled if UseRoaming is true and the server
supports it.
ok markus@
- reyk@cvs.openbsd.org 2009/10/28 16:38:18
[ssh_config.5 sshd.c misc.h ssh-keyscan.1 readconf.h sshconnect.c
channels.c channels.h servconf.h servconf.c ssh.1 ssh-keyscan.c scp.1
sftp.1 sshd_config.5 readconf.c ssh.c misc.c]
Allow to set the rdomain in ssh/sftp/scp/sshd and ssh-keyscan.
ok markus@
- jmc@cvs.openbsd.org 2009/10/28 21:45:08
[sshd_config.5 sftp.1]
tweak previous;
- djm@cvs.openbsd.org 2009/11/10 02:56:22
[ssh_config.5]
explain the constraints on LocalCommand some more so people don't
try to abuse it.
- djm@cvs.openbsd.org 2009/11/10 02:58:56
[sshd_config.5]
clarify that StrictModes does not apply to ChrootDirectory. Permissions
and ownership are always checked when chrooting. bz#1532
- dtucker@cvs.openbsd.org 2009/11/10 04:30:45
[sshconnect2.c channels.c sshconnect.c]
Set close-on-exec on various descriptors so they don't get leaked to
child processes. bz #1643, patch from jchadima at redhat, ok deraadt.
- markus@cvs.openbsd.org 2009/11/11 21:37:03
[channels.c channels.h]
fix race condition in x11/agent channel allocation: don't read after
the end of the select read/write fdset and make sure a reused FD
is not touched before the pre-handlers are called.
with and ok djm@
- djm@cvs.openbsd.org 2009/11/17 05:31:44
[clientloop.c]
fix incorrect exit status when multiplexing and channel ID 0 is recycled
bz#1570 reported by peter.oliver AT eon-is.co.uk; ok dtucker
- djm@cvs.openbsd.org 2009/11/19 23:39:50
[session.c]
bz#1606: error when an attempt is made to connect to a server
with ForceCommand=internal-sftp with a shell session (i.e. not a
subsystem session). Avoids stuck client when attempting to ssh to such a
service. ok dtucker@
- dtucker@cvs.openbsd.org 2009/11/20 00:15:41
[session.c]
Warn but do not fail if stat()ing the subsystem binary fails. This helps
with chrootdirectory+forcecommand=sftp-server and restricted shells.
bz #1599, ok djm.
- djm@cvs.openbsd.org 2009/11/20 00:54:01
[sftp.c]
bz#1588 change "Connecting to host..." message to "Connected to host."
and delay it until after the sftp protocol connection has been established.
Avoids confusing sequence of messages when the underlying ssh connection
experiences problems. ok dtucker@
- dtucker@cvs.openbsd.org 2009/11/20 00:59:36
[sshconnect2.c]
Use the HostKeyAlias when prompting for passwords. bz#1039, ok djm@
- djm@cvs.openbsd.org 2009/11/20 03:24:07
[misc.c]
correct off-by-one in percent_expand(): we would fatal() when trying
to expand EXPAND_MAX_KEYS, allowing only EXPAND_MAX_KEYS-1 to actually
work. Note that nothing in OpenSSH actually uses close to this limit at
present. bz#1607 from Jan.Pechanec AT Sun.COM
- halex@cvs.openbsd.org 2009/11/22 13:18:00
[sftp.c]
make passing of zero-length arguments to ssh safe by
passing "-<switch>" "<value>" rather than "-<switch><value>"
ok dtucker@, guenther@, djm@
- dtucker@cvs.openbsd.org 2009/12/06 23:41:15
[sshconnect2.c]
zap unused variable and strlen; from Steve McClellan, ok djm
- djm@cvs.openbsd.org 2009/12/06 23:53:45
[roaming_common.c]
use socklen_t for getsockopt optlen parameter; reported by
Steve.McClellan AT radisys.com, ok dtucker@
- dtucker@cvs.openbsd.org 2009/12/06 23:53:54
[sftp.c]
fix potential divide-by-zero in sftp's "df" output when talking to a server
that reports zero files on the filesystem (Unix filesystems always have at
least the root inode). From Steve McClellan at radisys, ok djm@
- markus@cvs.openbsd.org 2009/12/11 18:16:33
[key.c]
switch from 35 to the more common value of RSA_F4 == (2**16)+1 == 65537
for the RSA public exponent; discussed with provos; ok djm@
- guenther@cvs.openbsd.org 2009/12/20 07:28:36
[ssh.c sftp.c scp.c]
When passing user-controlled options with arguments to other programs,
pass the option and option argument as separate argv entries and
not smashed into one (e.g., as -l foo and not -lfoo). Also, always
pass a "--" argument to stop option parsing, so that a positional
argument that starts with a '-' isn't treated as an option. This
fixes some error cases as well as the handling of hostnames and
filenames that start with a '-'.
Based on a diff by halex@
ok halex@ djm@ deraadt@
- djm@cvs.openbsd.org 2009/12/20 23:20:40
[PROTOCOL]
fix an incorrect magic number and typo in PROTOCOL; bz#1688
report and fix from ueno AT unixuser.org
- stevesk@cvs.openbsd.org 2009/12/25 19:40:21
[readconf.c servconf.c misc.h ssh-keyscan.c misc.c]
validate routing domain is in range 0-RT_TABLEID_MAX.
'Looks right' deraadt@
- stevesk@cvs.openbsd.org 2009/12/29 16:38:41
[sshd_config.5 readconf.c ssh_config.5 scp.1 servconf.c sftp.1 ssh.1]
Rename RDomain config option to RoutingDomain to be more clear and
consistent with other options.
NOTE: if you currently use RDomain in the ssh client or server config,
or ssh/sshd -o, you must update to use RoutingDomain.
ok markus@ djm@
- jmc@cvs.openbsd.org 2009/12/29 18:03:32
[sshd_config.5 ssh_config.5]
sort previous;
- dtucker@cvs.openbsd.org 2010/01/04 01:45:30
[sshconnect2.c]
Don't escape backslashes in the SSH2 banner. bz#1533, patch from
Michal Gorny via Gentoo.
- djm@cvs.openbsd.org 2010/01/04 02:03:57
[sftp.c]
Implement tab-completion of commands, local and remote filenames for sftp.
Hacked on and off for some time by myself, mouring, Carlos Silva (via 2009
Google Summer of Code) and polished to a fine sheen by myself again.
It should deal more-or-less correctly with the ikky corner-cases presented
by quoted filenames, but the UI could still be slightly improved.
In particular, it is quite slow for remote completion on large directories.
bz#200; ok markus@
- djm@cvs.openbsd.org 2010/01/04 02:25:15
[sftp-server.c]
bz#1566 don't unnecessarily dup() in and out fds for sftp-server;
ok markus@
- dtucker@cvs.openbsd.org 2010/01/08 21:50:49
[sftp.c]
Fix two warnings: possibly used unitialized and use a nul byte instead of
NULL pointer. ok djm@
- (dtucker) [Makefile.in added roaming_client.c roaming_serv.c] Import new
files for roaming and add to Makefile.
- (dtucker) [Makefile.in] .c files do not belong in the OBJ lines.
- (dtucker) [sftp.c] ifdef out the sftp completion bits for platforms that
don't have libedit.
- (dtucker) [configure.ac misc.c readconf.c servconf.c ssh-keyscan.c] Make
RoutingDomain an unsupported option on platforms that don't have it.
- (dtucker) [sftp.c] Expand ifdef for libedit to cover complete_is_remote
too.
- (dtucker) [misc.c] Move the routingdomain ifdef to allow the socket to
be created.
- (dtucker] [misc.c] Shrink the area covered by USE_ROUTINGDOMAIN more
to eliminate an unused variable warning.
- (dtucker) [roaming_serv.c] Include includes.h for u_intXX_t types.
20091226
- (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1
Gzip all man pages. Patch from Corinna Vinschen.
20091221
- (dtucker) [auth-krb5.c platform.{c,h} openbsd-compat/port-aix.{c,h}]
Bug #1583: Use system's kerberos principal name on AIX if it's available.
Based on a patch from and tested by Miguel Sanders
20091208
- (dtucker) Bug #1470: Disable OOM-killing of the listening sshd on Linux,
based on a patch from Vaclav Ovsik and Colin Watson. ok djm.
20091207
- (dtucker) Bug #1160: use pkg-config for opensc config if it's available.
Tested by Martin Paljak.
- (dtucker) Bug #1677: add conditionals around the source for ssh-askpass.
20091121
- (tim) [opensshd.init.in] If PidFile is set in sshd_config, use it.
Bug 1628. OK dtucker@
20091120
- (djm) [ssh-rand-helper.c] Print error and usage() when passed command-
line arguments as none are supported. Exit when passed unrecognised
commandline flags. bz#1568 from gson AT araneus.fi
20091118
- (djm) [channels.c misc.c misc.h sshd.c] add missing setsockopt() to
set IPV6_V6ONLY for local forwarding with GatwayPorts=yes. Unify
setting IPV6_V6ONLY behind a new function misc.c:sock_set_v6only()
bz#1648, report and fix from jan.kratochvil AT redhat.com
- (djm) [contrib/gnome-ssh-askpass2.c] Make askpass dialog desktop-modal.
bz#1645, patch from jchadima AT redhat.com
20091107
- (dtucker) [authfile.c] Fall back to 3DES for the encryption of private
keys when built with OpenSSL versions that don't do AES.
20091105
- (dtucker) [authfile.c] Add OpenSSL compat header so this still builds with
older versions of OpenSSL.
20091024
- (dtucker) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2009/10/11 23:03:15
[hostfile.c]
mention the host name that we are looking for in check_host_in_hostfile()
- sobrado@cvs.openbsd.org 2009/10/17 12:10:39
[sftp-server.c]
sort flags.
- sobrado@cvs.openbsd.org 2009/10/22 12:35:53
[ssh.1 ssh-agent.1 ssh-add.1]
use the UNIX-related macros (.At and .Ux) where appropriate.
ok jmc@
- sobrado@cvs.openbsd.org 2009/10/22 15:02:12
[ssh-agent.1 ssh-add.1 ssh.1]
write UNIX-domain in a more consistent way; while here, replace a
few remaining ".Tn UNIX" macros with ".Ux" ones.
pointed out by ratchov@, thanks!
ok jmc@
- djm@cvs.openbsd.org 2009/10/22 22:26:13
[authfile.c]
switch from 3DES to AES-128 for encryption of passphrase-protected
SSH protocol 2 private keys; ok several
- djm@cvs.openbsd.org 2009/10/23 01:57:11
[sshconnect2.c]
disallow a hostile server from checking jpake auth by sending an
out-of-sequence success message. (doesn't affect code enabled by default)
- dtucker@cvs.openbsd.org 2009/10/24 00:48:34
[ssh-keygen.1]
ssh-keygen now uses AES-128 for private keys
- (dtucker) [mdoc2man.awk] Teach it to understand the .Ux macro.
- (dtucker) [session.c openbsd-compat/port-linux.{c,h}] Bug #1637: if selinux
is enabled set the security context to "sftpd_t" before running the
internal sftp server Based on a patch from jchadima at redhat.
20091011
- (dtucker) [configure.ac sftp-client.c] Remove the gyrations required for
dirent d_type and DTTOIF as we've switched OpenBSD to the more portable
lstat.
- (dtucker) OpenBSD CVS Sync
- markus@cvs.openbsd.org 2009/10/08 14:03:41
[sshd_config readconf.c ssh_config.5 servconf.c sshd_config.5]
disable protocol 1 by default (after a transition period of about 10 years)
ok deraadt
- jmc@cvs.openbsd.org 2009/10/08 20:42:12
[sshd_config.5 ssh_config.5 sshd.8 ssh.1]
some tweaks now that protocol 1 is not offered by default; ok markus
- dtucker@cvs.openbsd.org 2009/10/11 10:41:26
[sftp-client.c]
d_type isn't portable so use lstat to get dirent modes. Suggested by and
"looks sane" deraadt@
- markus@cvs.openbsd.org 2009/10/08 18:04:27
[regress/test-exec.sh]
re-enable protocol v1 for the tests.
20091007
- (dtucker) OpenBSD CVS Sync
- djm@cvs.openbsd.org 2009/08/12 00:13:00
[sftp.c sftp.1]
support most of scp(1)'s commandline arguments in sftp(1), as a first
step towards making sftp(1) a drop-in replacement for scp(1).
One conflicting option (-P) has not been changed, pending further
discussion.
Patch from carlosvsilvapt@gmail.com as part of his work in the
Google Summer of Code
- jmc@cvs.openbsd.org 2009/08/12 06:31:42
[sftp.1]
sort options;
- djm@cvs.openbsd.org 2009/08/13 01:11:19
[sftp.1 sftp.c]
Swizzle options: "-P sftp_server_path" moves to "-D sftp_server_path",
add "-P port" to match scp(1). Fortunately, the -P option is only really
used by our regression scripts.
part of larger patch from carlosvsilvapt@gmail.com for his Google Summer
of Code work; ok deraadt markus
- jmc@cvs.openbsd.org 2009/08/13 13:39:54
[sftp.1 sftp.c]
sync synopsis and usage();
- djm@cvs.openbsd.org 2009/08/14 18:17:49
[sftp-client.c]
make the "get_handle: ..." error messages vaguely useful by allowing
callers to specify their own error message strings.
- fgsch@cvs.openbsd.org 2009/08/15 18:56:34
[auth.h]
remove unused define. markus@ ok.
(Id sync only, Portable still uses this.)
- dtucker@cvs.openbsd.org 2009/08/16 23:29:26
[sshd_config.5]
Add PubkeyAuthentication to the list allowed in a Match block (bz #1577)
- djm@cvs.openbsd.org 2009/08/18 18:36:21
[sftp-client.h sftp.1 sftp-client.c sftp.c]
recursive transfer support for get/put and on the commandline
work mostly by carlosvsilvapt@gmail.com for the Google Summer of Code
with some tweaks by me; "go for it" deraadt@
- djm@cvs.openbsd.org 2009/08/18 21:15:59
[sftp.1]
fix "get" command usage, spotted by jmc@
- jmc@cvs.openbsd.org 2009/08/19 04:56:03
[sftp.1]
ether -> either;
- dtucker@cvs.openbsd.org 2009/08/20 23:54:28
[mux.c]
subsystem_flag is defined in ssh.c so it's extern; ok djm
- djm@cvs.openbsd.org 2009/08/27 17:28:52
[sftp-server.c]
allow setting an explicit umask on the commandline to override whatever
default the user has. bz#1229; ok dtucker@ deraadt@ markus@
- djm@cvs.openbsd.org 2009/08/27 17:33:49
[ssh-keygen.c]
force use of correct hash function for random-art signature display
as it was inheriting the wrong one when bubblebabble signatures were
activated; bz#1611 report and patch from fwojcik+openssh AT besh.com;
ok markus@
- djm@cvs.openbsd.org 2009/08/27 17:43:00
[sftp-server.8]
allow setting an explicit umask on the commandline to override whatever
default the user has. bz#1229; ok dtucker@ deraadt@ markus@
- djm@cvs.openbsd.org 2009/08/27 17:44:52
[authfd.c ssh-add.c authfd.h]
Do not fall back to adding keys without contraints (ssh-add -c / -t ...)
when the agent refuses the constrained add request. This was a useful
migration measure back in 2002 when constraints were new, but just
adds risk now.
bz #1612, report and patch from dkg AT fifthhorseman.net; ok markus@
- djm@cvs.openbsd.org 2009/08/31 20:56:02
[sftp-server.c]
check correct variable for error message, spotted by martynas@
- djm@cvs.openbsd.org 2009/08/31 21:01:29
[sftp-server.8]
document -e and -h; prodded by jmc@
- djm@cvs.openbsd.org 2009/09/01 14:43:17
[ssh-agent.c]
fix a race condition in ssh-agent that could result in a wedged or
spinning agent: don't read off the end of the allocated fd_sets, and
don't issue blocking read/write on agent sockets - just fall back to
select() on retriable read/write errors. bz#1633 reported and tested
by "noodle10000 AT googlemail.com"; ok dtucker@ markus@
- grunk@cvs.openbsd.org 2009/10/01 11:37:33
[dh.c]
fix a cast
ok djm@ markus@
- djm@cvs.openbsd.org 2009/10/06 04:46:40
[session.c]
bz#1596: fflush(NULL) before exec() to ensure that everying (motd
in particular) has made it out before the streams go away.
- djm@cvs.openbsd.org 2008/12/07 22:17:48
[regress/addrmatch.sh]
match string "passwordauthentication" only at start of line, not anywhere
in sshd -T output
- dtucker@cvs.openbsd.org 2009/05/05 07:51:36
[regress/multiplex.sh]
Always specify ssh_config for multiplex tests: prevents breakage caused
by options in ~/.ssh/config. From Dan Peterson.
- djm@cvs.openbsd.org 2009/08/13 00:57:17
[regress/Makefile]
regression test for port number parsing. written as part of the a2port
change that went into 5.2 but I forgot to commit it at the time...
- djm@cvs.openbsd.org 2009/08/13 01:11:55
[regress/sftp-batch.sh regress/sftp-badcmds.sh regress/sftp.sh
regress/sftp-cmds.sh regres/sftp-glob.sh]
date: 2009/08/13 01:11:19; author: djm; state: Exp; lines: +10 -7
Swizzle options: "-P sftp_server_path" moves to "-D sftp_server_path",
add "-P port" to match scp(1). Fortunately, the -P option is only really
used by our regression scripts.
part of larger patch from carlosvsilvapt@gmail.com for his Google Summer
of Code work; ok deraadt markus
- djm@cvs.openbsd.org 2009/08/20 18:43:07
[regress/ssh-com-sftp.sh]
fix one sftp -D ... => sftp -P ... conversion that I missed; from Carlos
Silva for Google Summer of Code
- dtucker@cvs.openbsd.org 2009/10/06 23:51:49
[regress/ssh2putty.sh]
Add OpenBSD tag to make syncs easier
- (dtucker) [regress/portnum.sh] Import new test.
- (dtucker) [configure.ac sftp-client.c] DTOTIF is in fs/ffs/dir.h on at
least dragonflybsd.
- (dtucker) d_type is not mandated by POSIX, so add fallback code using
stat(), needed on at least cygwin.
20091002
- (djm) [Makefile.in] Mention readconf.o in ssh-keysign's make deps.
spotted by des AT des.no
20090926 20090926
- (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec] - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
[contrib/suse/openssh.spec] Update for release [contrib/suse/openssh.spec] Update for release

View File

@ -208,10 +208,6 @@ are installed.
--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to --with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to
real (AF_INET) IPv4 addresses. Works around some quirks on Linux. 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 If you need to pass special options to the compiler or linker, you
can specify these as environment variables before running ./configure. can specify these as environment variables before running ./configure.
For example: For example:
@ -266,4 +262,4 @@ Please refer to the "reporting bugs" section of the webpage at
http://www.openssh.com/ http://www.openssh.com/
$Id: INSTALL,v 1.84 2007/08/17 12:52:05 dtucker Exp $ $Id: INSTALL,v 1.85 2010/02/11 22:34:22 djm Exp $

View File

@ -6,8 +6,8 @@ filexfer protocol described in:
http://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt http://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
Features from newer versions of the draft are not supported, unless Newer versions of the draft will not be supported, though some features
explicitly implemented as extensions described below. are individually implemented as extensions described below.
The protocol used by OpenSSH's ssh-agent is described in the file The protocol used by OpenSSH's ssh-agent is described in the file
PROTOCOL.agent PROTOCOL.agent
@ -31,7 +31,14 @@ The method is documented in:
http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
3. connection: Channel write close extension "eow@openssh.com" 3. transport: New public key algorithms "ssh-rsa-cert-v00@openssh.com" and
"ssh-dsa-cert-v00@openssh.com"
OpenSSH introduces two new public key algorithms to support certificate
authentication for users and hostkeys. These methods are documented in
the file PROTOCOL.certkeys
4. connection: Channel write close extension "eow@openssh.com"
The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF
message to allow an endpoint to signal its peer that it will send no message to allow an endpoint to signal its peer that it will send no
@ -70,7 +77,7 @@ message is only sent to OpenSSH peers (identified by banner).
Other SSH implementations may be whitelisted to receive this message Other SSH implementations may be whitelisted to receive this message
upon request. upon request.
4. connection: disallow additional sessions extension 5. connection: disallow additional sessions extension
"no-more-sessions@openssh.com" "no-more-sessions@openssh.com"
Most SSH connections will only ever request a single session, but a Most SSH connections will only ever request a single session, but a
@ -98,7 +105,7 @@ of this message, the no-more-sessions request is only sent to OpenSSH
servers (identified by banner). Other SSH implementations may be servers (identified by banner). Other SSH implementations may be
whitelisted to receive this message upon request. whitelisted to receive this message upon request.
5. connection: Tunnel forward extension "tun@openssh.com" 6. connection: Tunnel forward extension "tun@openssh.com"
OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com" OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com"
channel type. This channel type supports forwarding of network packets channel type. This channel type supports forwarding of network packets
@ -121,10 +128,10 @@ layer 2 frames or layer 3 packets. It may take one of the following values:
SSH_TUNMODE_ETHERNET 2 /* layer 2 frames */ SSH_TUNMODE_ETHERNET 2 /* layer 2 frames */
The "tunnel unit number" specifies the remote interface number, or may The "tunnel unit number" specifies the remote interface number, or may
be zero to allow the server to automatically chose an interface. A server be 0x7fffffff to allow the server to automatically chose an interface. A
that is not willing to open a client-specified unit should refuse the server that is not willing to open a client-specified unit should refuse
request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful open, the request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful
the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS. open, the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS.
Once established the client and server may exchange packet or frames Once established the client and server may exchange packet or frames
over the tunnel channel by encapsulating them in SSH protocol strings over the tunnel channel by encapsulating them in SSH protocol strings
@ -151,7 +158,7 @@ It may be one of:
The "packet data" field consists of the IPv4/IPv6 datagram itself The "packet data" field consists of the IPv4/IPv6 datagram itself
without any link layer header. without any link layer header.
The contents of the "data" field for layer 3 packets is: The contents of the "data" field for layer 2 packets is:
uint32 packet length uint32 packet length
byte[packet length] frame byte[packet length] frame
@ -159,7 +166,7 @@ The contents of the "data" field for layer 3 packets is:
The "frame" field contains an IEEE 802.3 Ethernet frame, including The "frame" field contains an IEEE 802.3 Ethernet frame, including
header. header.
6. sftp: Reversal of arguments to SSH_FXP_SYMLINK 7. sftp: Reversal of arguments to SSH_FXP_SYMLINK
When OpenSSH's sftp-server was implemented, the order of the arguments When OpenSSH's sftp-server was implemented, the order of the arguments
to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately, to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
@ -172,7 +179,7 @@ SSH_FXP_SYMLINK as follows:
string targetpath string targetpath
string linkpath string linkpath
7. sftp: Server extension announcement in SSH_FXP_VERSION 8. sftp: Server extension announcement in SSH_FXP_VERSION
OpenSSH's sftp-server lists the extensions it supports using the OpenSSH's sftp-server lists the extensions it supports using the
standard extension announcement mechanism in the SSH_FXP_VERSION server standard extension announcement mechanism in the SSH_FXP_VERSION server
@ -193,7 +200,7 @@ ever changed in an incompatible way. The server MAY advertise the same
extension with multiple versions (though this is unlikely). Clients MUST extension with multiple versions (though this is unlikely). Clients MUST
check the version number before attempting to use the extension. check the version number before attempting to use the extension.
8. sftp: Extension request "posix-rename@openssh.com" 9. sftp: Extension request "posix-rename@openssh.com"
This operation provides a rename operation with POSIX semantics, which This operation provides a rename operation with POSIX semantics, which
are different to those provided by the standard SSH_FXP_RENAME in are different to those provided by the standard SSH_FXP_RENAME in
@ -210,7 +217,7 @@ rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
This extension is advertised in the SSH_FXP_VERSION hello with version This extension is advertised in the SSH_FXP_VERSION hello with version
"1". "1".
9. sftp: Extension requests "statvfs@openssh.com" and 10. sftp: Extension requests "statvfs@openssh.com" and
"fstatvfs@openssh.com" "fstatvfs@openssh.com"
These requests correspond to the statvfs and fstatvfs POSIX system These requests correspond to the statvfs and fstatvfs POSIX system
@ -251,4 +258,4 @@ The values of the f_flag bitmask are as follows:
Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
advertised in the SSH_FXP_VERSION hello with version "2". advertised in the SSH_FXP_VERSION hello with version "2".
$OpenBSD: PROTOCOL,v 1.12 2009/02/14 06:35:49 djm Exp $ $OpenBSD: PROTOCOL,v 1.15 2010/02/26 20:29:54 djm Exp $

View File

@ -173,6 +173,15 @@ be added using the following request
string key_comment string key_comment
constraint[] key_constraints constraint[] key_constraints
DSA certificates may be added with:
byte SSH2_AGENTC_ADD_IDENTITY or
SSH2_AGENTC_ADD_ID_CONSTRAINED
string "ssh-dss-cert-v00@openssh.com"
string certificate
mpint dsa_private_key
string key_comment
constraint[] key_constraints
RSA keys may be added with this request: RSA keys may be added with this request:
byte SSH2_AGENTC_ADD_IDENTITY or byte SSH2_AGENTC_ADD_IDENTITY or
@ -187,6 +196,19 @@ RSA keys may be added with this request:
string key_comment string key_comment
constraint[] key_constraints constraint[] key_constraints
RSA certificates may be added with this request:
byte SSH2_AGENTC_ADD_IDENTITY or
SSH2_AGENTC_ADD_ID_CONSTRAINED
string "ssh-rsa-cert-v00@openssh.com"
string certificate
mpint rsa_d
mpint rsa_iqmp
mpint rsa_p
mpint rsa_q
string key_comment
constraint[] key_constraints
Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse
order to the protocol 1 add keys message. As with the corresponding order to the protocol 1 add keys message. As with the corresponding
protocol 1 "add key" request, the private key is overspecified to avoid protocol 1 "add key" request, the private key is overspecified to avoid
@ -513,4 +535,4 @@ Locking and unlocking affects both protocol 1 and protocol 2 keys.
SSH_AGENT_CONSTRAIN_LIFETIME 1 SSH_AGENT_CONSTRAIN_LIFETIME 1
SSH_AGENT_CONSTRAIN_CONFIRM 2 SSH_AGENT_CONSTRAIN_CONFIRM 2
$OpenBSD: PROTOCOL.agent,v 1.4 2008/07/01 23:12:47 stevesk Exp $ $OpenBSD: PROTOCOL.agent,v 1.5 2010/02/26 20:29:54 djm Exp $

View File

@ -0,0 +1,193 @@
This document describes a simple public-key certificate authentication
system for use by SSH.
Background
----------
The SSH protocol currently supports a simple public key authentication
mechanism. Unlike other public key implementations, SSH eschews the
use of X.509 certificates and uses raw keys. This approach has some
benefits relating to simplicity of configuration and minimisation
of attack surface, but it does not support the important use-cases
of centrally managed, passwordless authentication and centrally
certified host keys.
These protocol extensions build on the simple public key authentication
system already in SSH to allow certificate-based authentication.
The certificates used are not traditional X.509 certificates, with
numerous options and complex encoding rules, but something rather
more minimal: a key, some identity information and usage constraints
that have been signed with some other trusted key.
A sshd server may be configured to allow authentication via certified
keys, by extending the existing ~/.ssh/authorized_keys mechanism
to allow specification of certification authority keys in addition
to raw user keys. The ssh client will support automatic verification
of acceptance of certified host keys, by adding a similar ability
to specify CA keys in ~/.ssh/known_hosts.
Certified keys are represented using two new key types:
ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com that
include certification information along with the public key that is used
to sign challenges. ssh-keygen performs the CA signing operation.
Protocol extensions
-------------------
The SSH wire protocol includes several extensibility mechanisms.
These modifications shall take advantage of namespaced public key
algorithm names to add support for certificate authentication without
breaking the protocol - implementations that do not support the
extensions will simply ignore them.
Authentication using the new key formats described below proceeds
using the existing SSH "publickey" authentication method described
in RFC4252 section 7.
New public key formats
----------------------
The ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com key
types take a similar high-level format (note: data types and
encoding are as per RFC4251 section 5). The serialised wire encoding of
these certificates is also used for storing them on disk.
#define SSH_CERT_TYPE_USER 1
#define SSH_CERT_TYPE_HOST 2
RSA certificate
string "ssh-rsa-cert-v00@openssh.com"
mpint e
mpint n
uint32 type
string key id
string valid principals
uint64 valid after
uint64 valid before
string constraints
string nonce
string reserved
string signature key
string signature
DSA certificate
string "ssh-dss-cert-v00@openssh.com"
mpint p
mpint q
mpint g
mpint y
uint32 type
string key id
string valid principals
uint64 valid after
uint64 valid before
string constraints
string nonce
string reserved
string signature key
string signature
e and n are the RSA exponent and public modulus respectively.
p, q, g, y are the DSA parameters as described in FIPS-186-2.
type specifies whether this certificate is for identification of a user
or a host using a SSH_CERT_TYPE_... value.
key id is a free-form text field that is filled in by the CA at the time
of signing; the intention is that the contents of this field are used to
identify the identity principal in log messages.
"valid principals" is a string containing zero or more principals as
strings packed inside it. These principals list the names for which this
certificate is valid; hostnames for SSH_CERT_TYPE_HOST certificates and
usernames for SSH_CERT_TYPE_USER certificates. As a special case, a
zero-length "valid principals" field means the certificate is valid for
any principal of the specified type. XXX DNS wildcards?
"valid after" and "valid before" specify a validity period for the
certificate. Each represents a time in seconds since 1970-01-01
00:00:00. A certificate is considered valid if:
valid after <= current time < valid before
constraints is a set of zero or more key constraints encoded as below.
The nonce field is a CA-provided random bitstring of arbitrary length
(but typically 16 or 32 bytes) included to make attacks that depend on
inducing collisions in the signature hash infeasible.
The reserved field is current unused and is ignored in this version of
the protocol.
signature key contains the CA key used to sign the certificate.
The valid key types for CA keys are ssh-rsa and ssh-dss. "Chained"
certificates, where the signature key type is a certificate type itself
are NOT supported. Note that it is possible for a RSA certificate key to
be signed by a DSS CA key and vice-versa.
signature is computed over all preceding fields from the initial string
up to, and including the signature key. Signatures are computed and
encoded according to the rules defined for the CA's public key algorithm
(RFC4253 section 6.6 for ssh-rsa and ssh-dss).
Constraints
-----------
The constraints section of the certificate specifies zero or more
constraints on the certificates validity. The format of this field
is a sequence of zero or more tuples:
string name
string data
The name field identifies the constraint and the data field encodes
constraint-specific information (see below). All constraints are
"critical", if an implementation does not recognise a constraint
then the validating party should refuse to accept the certificate.
The supported constraints and the contents and structure of their
data fields are:
Name Format Description
-----------------------------------------------------------------------------
force-command string Specifies a command that is executed
(replacing any the user specified on the
ssh command-line) whenever this key is
used for authentication.
permit-X11-forwarding empty Flag indicating that X11 forwarding
should be permitted. X11 forwarding will
be refused if this constraint is absent.
permit-agent-forwarding empty Flag indicating that agent forwarding
should be allowed. Agent forwarding
must not be permitted unless this
constraint is present.
permit-port-forwarding empty Flag indicating that port-forwarding
should be allowed. If this constraint is
not present then no port forwarding will
be allowed.
permit-pty empty Flag indicating that PTY allocation
should be permitted. In the absence of
this constraint PTY allocation will be
disabled.
permit-user-rc empty Flag indicating that execution of
~/.ssh/rc should be permitted. Execution
of this script will not be permitted if
this constraint is not present.
source-address string Comma-separated list of source addresses
from which this certificate is accepted
for authentication. Addresses are
specified in CIDR format (nn.nn.nn.nn/nn
or hhhh::hhhh/nn).
If this constraint is not present then
certificates may be presented from any
source address.
$OpenBSD: PROTOCOL.certkeys,v 1.3 2010/03/03 22:50:40 djm Exp $

196
crypto/openssh/PROTOCOL.mux Normal file
View File

@ -0,0 +1,196 @@
This document describes the multiplexing protocol used by ssh(1)'s
ControlMaster connection-sharing.
Most messages from the client to the server contain a "request id" field.
This field is returned in replies as "client request id" to facilitate
matching of responses to requests.
1. Connection setup
When a multiplexing connection is made to a ssh(1) operating as a
ControlMaster from a ssh(1) in multiplex slave mode, the first
action of each is to exchange hello messages:
uint32 MUX_MSG_HELLO
uint32 protocol version
string extension name [optional]
string extension value [optional]
...
The current version of the mux protocol is 4. A slave should refuse
to connect to a master that speaks an unsupported protocol version.
Following the version identifier are zero or more extensions
represented as a name/value pair. No extensions are currently
defined.
2. Opening sessions
To open a new multiplexed session, a client may send the following
request:
uint32 MUX_C_MSG_NEW_SESSION
uint32 request id
string reserved
bool want tty flag
bool want X11 forwarding flag
bool want agent flag
bool subsystem flag
uint32 escape char
string terminal type
string command
string environment string 0 [optional]
...
To disable the use of an escape character, "escape char" may be set
to 0xffffffff. "terminal type" is generally set to the value of
$TERM. zero or more environment strings may follow the command.
The client then sends its standard input, output and error file
descriptors (in that order) using Unix domain socket control messages.
The contents of "reserved" are currently ignored.
If successful, the server will reply with MUX_S_SESSION_OPENED
uint32 MUX_S_SESSION_OPENED
uint32 client request id
uint32 session id
Otherwise it will reply with an error: MUX_S_PERMISSION_DENIED or
MUX_S_FAILURE.
Once the server has received the fds, it will respond with MUX_S_OK
indicating that the session is up. The client now waits for the
session to end. When it does, the server will send an exit status
message:
uint32 MUX_S_EXIT_MESSAGE
uint32 session id
uint32 exit value
The client should exit with this value to mimic the behaviour of a
non-multiplexed ssh(1) connection. Two additional cases that the
client must cope with are it receiving a signal itself and the
server disconnecting without sending an exit message.
3. Health checks
The client may request a health check/PID report from a server:
uint32 MUX_C_ALIVE_CHECK
uint32 request id
The server replies with:
uint32 MUX_S_ALIVE
uint32 client request id
uint32 server pid
4. Remotely terminating a master
A client may request that a master terminate immediately:
uint32 MUX_C_TERMINATE
uint32 request id
The server will reply with one of MUX_S_OK or MUX_S_PERMISSION_DENIED.
5. Requesting establishment of port forwards
A client may request the master to establish a port forward:
uint32 MUX_C_OPEN_FORWARD
uint32 request id
uint32 forwarding type
string listen host
string listen port
string connect host
string connect port
forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC.
A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
MUX_S_FAILURE.
5. Requesting closure of port forwards
A client may request the master to establish a port forward:
uint32 MUX_C_OPEN_FORWARD
uint32 request id
uint32 forwarding type
string listen host
string listen port
string connect host
string connect port
forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC.
A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
MUX_S_FAILURE.
6. Requesting stdio forwarding
A client may request the master to establish a stdio forwarding:
uint32 MUX_C_NEW_STDIO_FWD
uint32 request id
string reserved
string connect host
string connect port
The client then sends its standard input and output file descriptors
(in that order) using Unix domain socket control messages.
The contents of "reserved" are currently ignored.
A server may reply with a MUX_S_SESSION_OPEED, a MUX_S_PERMISSION_DENIED
or a MUX_S_FAILURE.
7. Status messages
The MUX_S_OK message is empty:
uint32 MUX_S_OK
uint32 client request id
The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
uint32 MUX_S_PERMISSION_DENIED
uint32 client request id
string reason
uint32 MUX_S_FAILURE
uint32 client request id
string reason
7. Protocol numbers
#define MUX_MSG_HELLO 0x00000001
#define MUX_C_NEW_SESSION 0x10000002
#define MUX_C_ALIVE_CHECK 0x10000004
#define MUX_C_TERMINATE 0x10000005
#define MUX_C_OPEN_FORWARD 0x10000006
#define MUX_C_CLOSE_FORWARD 0x10000007
#define MUX_S_OK 0x80000001
#define MUX_S_PERMISSION_DENIED 0x80000002
#define MUX_S_FAILURE 0x80000003
#define MUX_S_EXIT_MESSAGE 0x80000004
#define MUX_S_ALIVE 0x80000005
#define MUX_S_SESSION_OPENED 0x80000006
#define MUX_FWD_LOCAL 1
#define MUX_FWD_REMOTE 2
#define MUX_FWD_DYNAMIC 3
XXX TODO
XXX extended status (e.g. report open channels / forwards)
XXX graceful close (delete listening socket, but keep existing sessions active)
XXX lock (maybe)
XXX watch in/out traffic (pre/post crypto)
XXX inject packet (what about replies)
XXX server->client error/warning notifications
XXX port0 rfwd (need custom response message)
XXX send signals via mux
$OpenBSD: PROTOCOL.mux,v 1.1 2010/01/26 01:28:35 djm Exp $

View File

@ -1,4 +1,4 @@
See http://www.openssh.com/txt/release-5.3 for the release notes. See http://www.openssh.com/txt/release-5.4 for the release notes.
- A Japanese translation of this document and of the OpenSSH FAQ is - A Japanese translation of this document and of the OpenSSH FAQ is
- available at http://www.unixuser.org/~haruyama/security/openssh/index.html - available at http://www.unixuser.org/~haruyama/security/openssh/index.html
@ -62,4 +62,4 @@ References -
[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9 [6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9
[7] http://www.openssh.com/faq.html [7] http://www.openssh.com/faq.html
$Id: README,v 1.70.4.1 2009/09/26 04:11:47 djm Exp $ $Id: README,v 1.72 2010/03/07 22:41:02 djm Exp $

View File

@ -1,93 +0,0 @@
How to use smartcards with OpenSSH?
OpenSSH contains experimental support for authentication using
Cyberflex smartcards and TODOS card readers, in addition to the cards
with PKCS#15 structure supported by OpenSC. To enable this you
need to:
Using libsectok:
(1) enable sectok support in OpenSSH:
$ ./configure --with-sectok
(2) If you have used a previous version of ssh with your card, you
must remove the old applet and keys.
$ sectok
sectok> login -d
sectok> junload Ssh.bin
sectok> delete 0012
sectok> delete sh
sectok> quit
(3) load the Java Cardlet to the Cyberflex card and set card passphrase:
$ sectok
sectok> login -d
sectok> jload /usr/libdata/ssh/Ssh.bin
sectok> setpass
Enter new AUT0 passphrase:
Re-enter passphrase:
sectok> quit
Do not forget the passphrase. There is no way to
recover if you do.
IMPORTANT WARNING: If you attempt to login with the
wrong passphrase three times in a row, you will
destroy your card.
(4) load a RSA key to the card:
$ ssh-keygen -f /path/to/rsakey -U 1
(where 1 is the reader number, you can also try 0)
In spite of the name, this does not generate a key.
It just loads an already existing key on to the card.
(5) Optional: If you don't want to use a card passphrase, change the
acl on the private key file:
$ sectok
sectok> login -d
sectok> acl 0012 world: w
world: w
AUT0: w inval
sectok> quit
If you do this, anyone who has access to your card
can assume your identity. This is not recommended.
Using OpenSC:
(1) install OpenSC:
Sources and instructions are available from
http://www.opensc.org/
(2) enable OpenSC support in OpenSSH:
$ ./configure --with-opensc[=/path/to/opensc] [options]
(3) load a RSA key to the card:
Not supported yet.
Common operations:
(1) tell the ssh client to use the card reader:
$ ssh -I 1 otherhost
(2) or tell the agent (don't forget to restart) to use the smartcard:
$ ssh-add -s 1
-markus,
Tue Jul 17 23:54:51 CEST 2001
$OpenBSD: README.smartcard,v 1.9 2003/11/21 11:57:02 djm Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */ /* $OpenBSD: addrmatch.c,v 1.5 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org> * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
@ -126,6 +126,8 @@ addr_netmask(int af, u_int l, struct xaddr *n)
switch (af) { switch (af) {
case AF_INET: case AF_INET:
n->af = AF_INET; n->af = AF_INET;
if (l == 0)
return 0;
n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
return 0; return 0;
case AF_INET6: case AF_INET6:
@ -422,3 +424,77 @@ addr_match_list(const char *addr, const char *_list)
return ret; return ret;
} }
/*
* Match "addr" against list CIDR list "_list". Lexical wildcards and
* negation are not supported. If "addr" == NULL, will verify structure
* of "_list".
*
* Returns 1 on match found (never returned when addr == NULL).
* Returns 0 on if no match found, or no errors found when addr == NULL.
* Returns -1 on error
*/
int
addr_match_cidr_list(const char *addr, const char *_list)
{
char *list, *cp, *o;
struct xaddr try_addr, match_addr;
u_int masklen;
int ret = 0, r;
if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
debug2("%s: couldn't parse address %.100s", __func__, addr);
return 0;
}
if ((o = list = strdup(_list)) == NULL)
return -1;
while ((cp = strsep(&list, ",")) != NULL) {
if (*cp == '\0') {
error("%s: empty entry in list \"%.100s\"",
__func__, o);
ret = -1;
break;
}
/*
* NB. This function is called in pre-auth with untrusted data,
* so be extra paranoid about junk reaching getaddrino (via
* addr_pton_cidr).
*/
/* Stop junk from reaching getaddrinfo. +3 is for masklen */
if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
error("%s: list entry \"%.100s\" too long",
__func__, cp);
ret = -1;
break;
}
#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
error("%s: list entry \"%.100s\" contains invalid "
"characters", __func__, cp);
ret = -1;
}
/* Prefer CIDR address matching */
r = addr_pton_cidr(cp, &match_addr, &masklen);
if (r == -1) {
error("Invalid network entry \"%.100s\"", cp);
ret = -1;
break;
} else if (r == -2) {
error("Inconsistent mask length for "
"network \"%.100s\"", cp);
ret = -1;
break;
} else if (r == 0 && addr != NULL) {
if (addr_netmatch(&try_addr, &match_addr,
masklen) == 0)
ret = 1;
continue;
}
}
xfree(o);
return ret;
}

View File

@ -78,6 +78,11 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
krb5_error_code problem; krb5_error_code problem;
krb5_ccache ccache = NULL; krb5_ccache ccache = NULL;
int len; int len;
char *client, *platform_client;
/* get platform-specific kerberos client principal name (if it exists) */
platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name);
client = platform_client ? platform_client : authctxt->pw->pw_name;
temporarily_use_uid(authctxt->pw); temporarily_use_uid(authctxt->pw);
@ -85,7 +90,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
if (problem) if (problem)
goto out; goto out;
problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, problem = krb5_parse_name(authctxt->krb5_ctx, client,
&authctxt->krb5_user); &authctxt->krb5_user);
if (problem) if (problem)
goto out; goto out;
@ -141,8 +146,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
if (problem) if (problem)
goto out; goto out;
if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) {
authctxt->pw->pw_name)) {
problem = -1; problem = -1;
goto out; goto out;
} }
@ -176,6 +180,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
out: out:
restore_uid(); restore_uid();
if (platform_client != NULL)
xfree(platform_client);
if (problem) { if (problem) {
if (ccache) if (ccache)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-options.c,v 1.44 2009/01/22 10:09:16 djm Exp $ */ /* $OpenBSD: auth-options.c,v 1.48 2010/03/07 11:57:13 dtucker Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -44,6 +44,7 @@ int no_agent_forwarding_flag = 0;
int no_x11_forwarding_flag = 0; int no_x11_forwarding_flag = 0;
int no_pty_flag = 0; int no_pty_flag = 0;
int no_user_rc = 0; int no_user_rc = 0;
int key_is_cert_authority = 0;
/* "command=" option. */ /* "command=" option. */
char *forced_command = NULL; char *forced_command = NULL;
@ -64,6 +65,7 @@ auth_clear_options(void)
no_pty_flag = 0; no_pty_flag = 0;
no_x11_forwarding_flag = 0; no_x11_forwarding_flag = 0;
no_user_rc = 0; no_user_rc = 0;
key_is_cert_authority = 0;
while (custom_environment) { while (custom_environment) {
struct envstring *ce = custom_environment; struct envstring *ce = custom_environment;
custom_environment = ce->next; custom_environment = ce->next;
@ -76,7 +78,6 @@ auth_clear_options(void)
} }
forced_tun_device = -1; forced_tun_device = -1;
channel_clear_permitted_opens(); channel_clear_permitted_opens();
auth_debug_reset();
} }
/* /*
@ -96,6 +97,12 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
return 1; return 1;
while (*opts && *opts != ' ' && *opts != '\t') { while (*opts && *opts != ' ' && *opts != '\t') {
cp = "cert-authority";
if (strncasecmp(opts, cp, strlen(cp)) == 0) {
key_is_cert_authority = 1;
opts += strlen(cp);
goto next_option;
}
cp = "no-port-forwarding"; cp = "no-port-forwarding";
if (strncasecmp(opts, cp, strlen(cp)) == 0) { if (strncasecmp(opts, cp, strlen(cp)) == 0) {
auth_debug_add("Port forwarding disabled."); auth_debug_add("Port forwarding disabled.");
@ -356,9 +363,6 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
/* Process the next option. */ /* Process the next option. */
} }
if (!use_privsep)
auth_debug_send();
/* grant access */ /* grant access */
return 1; return 1;
@ -368,9 +372,158 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
auth_debug_add("Bad options in %.100s file, line %lu: %.50s", auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
file, linenum, opts); file, linenum, opts);
if (!use_privsep)
auth_debug_send();
/* deny access */ /* deny access */
return 0; return 0;
} }
/*
* Set options from certificate constraints. These supersede user key options
* so this must be called after auth_parse_options().
*/
int
auth_cert_constraints(Buffer *c_orig, struct passwd *pw)
{
u_char *name = NULL, *data_blob = NULL;
u_int nlen, dlen, clen;
Buffer c, data;
int ret = -1;
int cert_no_port_forwarding_flag = 1;
int cert_no_agent_forwarding_flag = 1;
int cert_no_x11_forwarding_flag = 1;
int cert_no_pty_flag = 1;
int cert_no_user_rc = 1;
char *cert_forced_command = NULL;
int cert_source_address_done = 0;
buffer_init(&data);
/* Make copy to avoid altering original */
buffer_init(&c);
buffer_append(&c, buffer_ptr(c_orig), buffer_len(c_orig));
while (buffer_len(&c) > 0) {
if ((name = buffer_get_string_ret(&c, &nlen)) == NULL ||
(data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) {
error("Certificate constraints corrupt");
goto out;
}
buffer_append(&data, data_blob, dlen);
debug3("found certificate constraint \"%.100s\" len %u",
name, dlen);
if (strlen(name) != nlen) {
error("Certificate constraint name contains \\0");
goto out;
}
if (strcmp(name, "permit-X11-forwarding") == 0)
cert_no_x11_forwarding_flag = 0;
else if (strcmp(name, "permit-agent-forwarding") == 0)
cert_no_agent_forwarding_flag = 0;
else if (strcmp(name, "permit-port-forwarding") == 0)
cert_no_port_forwarding_flag = 0;
else if (strcmp(name, "permit-pty") == 0)
cert_no_pty_flag = 0;
else if (strcmp(name, "permit-user-rc") == 0)
cert_no_user_rc = 0;
else if (strcmp(name, "force-command") == 0) {
char *command = buffer_get_string_ret(&data, &clen);
if (command == NULL) {
error("Certificate constraint \"%s\" corrupt",
name);
goto out;
}
if (strlen(command) != clen) {
error("force-command constrain contains \\0");
goto out;
}
if (cert_forced_command != NULL) {
error("Certificate has multiple "
"force-command constraints");
xfree(command);
goto out;
}
cert_forced_command = command;
} else if (strcmp(name, "source-address") == 0) {
char *allowed = buffer_get_string_ret(&data, &clen);
const char *remote_ip = get_remote_ipaddr();
if (allowed == NULL) {
error("Certificate constraint \"%s\" corrupt",
name);
goto out;
}
if (strlen(allowed) != clen) {
error("source-address constrain contains \\0");
goto out;
}
if (cert_source_address_done++) {
error("Certificate has multiple "
"source-address constraints");
xfree(allowed);
goto out;
}
switch (addr_match_cidr_list(remote_ip, allowed)) {
case 1:
/* accepted */
xfree(allowed);
break;
case 0:
/* no match */
logit("Authentication tried for %.100s with "
"valid certificate but not from a "
"permitted host (ip=%.200s).",
pw->pw_name, remote_ip);
auth_debug_add("Your address '%.200s' is not "
"permitted to use this certificate for "
"login.", remote_ip);
xfree(allowed);
goto out;
case -1:
error("Certificate source-address contents "
"invalid");
xfree(allowed);
goto out;
}
} else {
error("Certificate constraint \"%s\" is not supported",
name);
goto out;
}
if (buffer_len(&data) != 0) {
error("Certificate constraint \"%s\" corrupt "
"(extra data)", name);
goto out;
}
buffer_clear(&data);
xfree(name);
xfree(data_blob);
name = data_blob = NULL;
}
/* successfully parsed all constraints */
ret = 0;
no_port_forwarding_flag |= cert_no_port_forwarding_flag;
no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;
no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
no_pty_flag |= cert_no_pty_flag;
no_user_rc |= cert_no_user_rc;
/* CA-specified forced command supersedes key option */
if (cert_forced_command != NULL) {
if (forced_command != NULL)
xfree(forced_command);
forced_command = cert_forced_command;
}
out:
if (name != NULL)
xfree(name);
if (data_blob != NULL)
xfree(data_blob);
buffer_free(&data);
buffer_free(&c);
return ret;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-options.h,v 1.17 2008/03/26 21:28:14 djm Exp $ */ /* $OpenBSD: auth-options.h,v 1.18 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -30,8 +30,10 @@ extern int no_user_rc;
extern char *forced_command; extern char *forced_command;
extern struct envstring *custom_environment; extern struct envstring *custom_environment;
extern int forced_tun_device; extern int forced_tun_device;
extern int key_is_cert_authority;
int auth_parse_options(struct passwd *, char *, char *, u_long); int auth_parse_options(struct passwd *, char *, char *, u_long);
void auth_clear_options(void); void auth_clear_options(void);
int auth_cert_constraints(Buffer *, struct passwd *);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-rh-rsa.c,v 1.42 2006/08/03 03:34:41 deraadt Exp $ */ /* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -44,6 +44,9 @@ auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
{ {
HostStatus host_status; HostStatus host_status;
if (auth_key_is_revoked(client_host_key))
return 0;
/* Check if we would accept it using rhosts authentication. */ /* Check if we would accept it using rhosts authentication. */
if (!auth_rhosts(pw, cuser)) if (!auth_rhosts(pw, cuser))
return 0; return 0;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-rhosts.c,v 1.43 2008/06/13 14:18:51 dtucker Exp $ */ /* $OpenBSD: auth-rhosts.c,v 1.44 2010/03/07 11:57:13 dtucker Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -317,11 +317,5 @@ int
auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
const char *ipaddr) const char *ipaddr)
{ {
int ret; return auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
auth_debug_reset();
ret = auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
if (!use_privsep)
auth_debug_send();
return ret;
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */ /* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -94,6 +94,9 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
MD5_CTX md; MD5_CTX md;
int len; int len;
if (auth_key_is_revoked(key))
return 0;
/* don't allow short keys */ /* don't allow short keys */
if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.c,v 1.80 2008/11/04 07:58:09 djm Exp $ */ /* $OpenBSD: auth.c,v 1.86 2010/03/05 02:58:11 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -70,6 +70,7 @@ __RCSID("$FreeBSD$");
#ifdef GSSAPI #ifdef GSSAPI
#include "ssh-gss.h" #include "ssh-gss.h"
#endif #endif
#include "authfile.h"
#include "monitor_wrap.h" #include "monitor_wrap.h"
/* import */ /* import */
@ -96,7 +97,6 @@ allowed_user(struct passwd * pw)
{ {
struct stat st; struct stat st;
const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
char *shell;
u_int i; u_int i;
#ifdef USE_SHADOW #ifdef USE_SHADOW
struct spwd *spw = NULL; struct spwd *spw = NULL;
@ -154,22 +154,28 @@ allowed_user(struct passwd * pw)
} }
/* /*
* Get the shell from the password data. An empty shell field is * Deny if shell does not exist or is not executable unless we
* legal, and means /bin/sh. * are chrooting.
*/ */
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; if (options.chroot_directory == NULL ||
strcasecmp(options.chroot_directory, "none") == 0) {
char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
_PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
/* deny if shell does not exists or is not executable */ if (stat(shell, &st) != 0) {
if (stat(shell, &st) != 0) { logit("User %.100s not allowed because shell %.100s "
logit("User %.100s not allowed because shell %.100s does not exist", "does not exist", pw->pw_name, shell);
pw->pw_name, shell); xfree(shell);
return 0; return 0;
} }
if (S_ISREG(st.st_mode) == 0 || if (S_ISREG(st.st_mode) == 0 ||
(st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
logit("User %.100s not allowed because shell %.100s is not executable", logit("User %.100s not allowed because shell %.100s "
pw->pw_name, shell); "is not executable", pw->pw_name, shell);
return 0; xfree(shell);
return 0;
}
xfree(shell);
} }
if (options.num_deny_users > 0 || options.num_allow_users > 0 || if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
@ -456,7 +462,7 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,
return -1; return -1;
} }
/* If are passed the homedir then we can stop */ /* If are past the homedir then we can stop */
if (comparehome && strcmp(homedir, buf) == 0) { if (comparehome && strcmp(homedir, buf) == 0) {
debug3("secure_filename: terminating check at '%s'", debug3("secure_filename: terminating check at '%s'",
buf); buf);
@ -484,8 +490,12 @@ auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
* Open the file containing the authorized keys * Open the file containing the authorized keys
* Fail quietly if file does not exist * Fail quietly if file does not exist
*/ */
if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
if (errno != ENOENT)
debug("Could not open keyfile '%s': %s", file,
strerror(errno));
return NULL; return NULL;
}
if (fstat(fd, &st) < 0) { if (fstat(fd, &st) < 0) {
close(fd); close(fd);
@ -526,7 +536,28 @@ getpwnamallow(const char *user)
parse_server_match_config(&options, user, parse_server_match_config(&options, user,
get_canonical_hostname(options.use_dns), get_remote_ipaddr()); get_canonical_hostname(options.use_dns), get_remote_ipaddr());
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_setauthdb(user);
#endif
pw = getpwnam(user); pw = getpwnam(user);
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
aix_restoreauthdb();
#endif
#ifdef HAVE_CYGWIN
/*
* Windows usernames are case-insensitive. To avoid later problems
* when trying to match the username, the user is only allowed to
* login if the username is given in the same case as stored in the
* user database.
*/
if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
logit("Login name %.100s does not match stored username %.100s",
user, pw->pw_name);
pw = NULL;
}
#endif
if (pw == NULL) { if (pw == NULL) {
logit("Invalid user %.100s from %.100s", logit("Invalid user %.100s from %.100s",
user, get_remote_ipaddr()); user, get_remote_ipaddr());
@ -561,6 +592,35 @@ getpwnamallow(const char *user)
return (NULL); return (NULL);
} }
/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
int
auth_key_is_revoked(Key *key)
{
char *key_fp;
if (options.revoked_keys_file == NULL)
return 0;
switch (key_in_file(key, options.revoked_keys_file, 0)) {
case 0:
/* key not revoked */
return 0;
case -1:
/* Error opening revoked_keys_file: refuse all keys */
error("Revoked keys file is unreadable: refusing public key "
"authentication");
return 1;
case 1:
/* Key revoked */
key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
error("WARNING: authentication attempt with a revoked "
"%s key %s ", key_type(key), key_fp);
xfree(key_fp);
return 1;
}
fatal("key_in_file returned junk");
}
void void
auth_debug_add(const char *fmt,...) auth_debug_add(const char *fmt,...)
{ {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.62 2008/11/04 08:22:12 djm Exp $ */ /* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -171,6 +171,7 @@ char *authorized_keys_file(struct passwd *);
char *authorized_keys_file2(struct passwd *); char *authorized_keys_file2(struct passwd *);
FILE *auth_openkeyfile(const char *, struct passwd *, int); FILE *auth_openkeyfile(const char *, struct passwd *, int);
int auth_key_is_revoked(Key *);
HostStatus HostStatus
check_key_in_hostfiles(struct passwd *, Key *, const char *, check_key_in_hostfiles(struct passwd *, Key *, const char *,
@ -178,7 +179,8 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *,
/* hostkey handling */ /* hostkey handling */
Key *get_hostkey_by_index(int); Key *get_hostkey_by_index(int);
Key *get_hostkey_by_type(int); Key *get_hostkey_public_by_type(int);
Key *get_hostkey_private_by_type(int);
int get_hostkey_index(Key *); int get_hostkey_index(Key *);
int ssh1_session_key(BIGNUM *); int ssh1_session_key(BIGNUM *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 djm Exp $ */ /* $OpenBSD: auth2-hostbased.c,v 1.13 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -145,6 +145,9 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
HostStatus host_status; HostStatus host_status;
int len; int len;
if (auth_key_is_revoked(key))
return 0;
resolvedname = get_canonical_hostname(options.use_dns); resolvedname = get_canonical_hostname(options.use_dns);
ipaddr = get_remote_ipaddr(); ipaddr = get_remote_ipaddr();

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.19 2008/07/03 21:46:58 otto Exp $ */ /* $OpenBSD: auth2-pubkey.c,v 1.21 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -32,6 +32,8 @@
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "xmalloc.h" #include "xmalloc.h"
@ -54,6 +56,7 @@
#endif #endif
#include "monitor_wrap.h" #include "monitor_wrap.h"
#include "misc.h" #include "misc.h"
#include "authfile.h"
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
@ -178,6 +181,7 @@ static int
user_key_allowed2(struct passwd *pw, Key *key, char *file) user_key_allowed2(struct passwd *pw, Key *key, char *file)
{ {
char line[SSH_MAX_PUBKEY_BYTES]; char line[SSH_MAX_PUBKEY_BYTES];
const char *reason;
int found_key = 0; int found_key = 0;
FILE *f; FILE *f;
u_long linenum = 0; u_long linenum = 0;
@ -196,11 +200,13 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
} }
found_key = 0; found_key = 0;
found = key_new(key->type); found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
char *cp, *key_options = NULL; char *cp, *key_options = NULL;
auth_clear_options();
/* Skip leading whitespace, empty and comment lines. */ /* Skip leading whitespace, empty and comment lines. */
for (cp = line; *cp == ' ' || *cp == '\t'; cp++) for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
; ;
@ -227,8 +233,32 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
continue; continue;
} }
} }
if (key_equal(found, key) && if (auth_parse_options(pw, key_options, file, linenum) != 1)
auth_parse_options(pw, key_options, file, linenum) == 1) { continue;
if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) {
if (!key_is_cert_authority)
continue;
if (!key_equal(found, key->cert->signature_key))
continue;
debug("matching CA found: file %s, line %lu",
file, linenum);
fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
verbose("Found matching %s CA: %s",
key_type(found), fp);
xfree(fp);
if (key_cert_check_authority(key, 0, 0, pw->pw_name,
&reason) != 0) {
error("%s", reason);
auth_debug_add("%s", reason);
continue;
}
if (auth_cert_constraints(&key->cert->constraints,
pw) != 0)
continue;
found_key = 1;
break;
} else if (!key_is_cert_authority && key_equal(found, key)) {
found_key = 1; found_key = 1;
debug("matching key found: file %s, line %lu", debug("matching key found: file %s, line %lu",
file, linenum); file, linenum);
@ -247,6 +277,47 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
return found_key; return found_key;
} }
/* Authenticate a certificate key against TrustedUserCAKeys */
static int
user_cert_trusted_ca(struct passwd *pw, Key *key)
{
char *key_fp, *ca_fp;
const char *reason;
int ret = 0;
if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
return 0;
key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
ca_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
if (key_in_file(key->cert->signature_key,
options.trusted_user_ca_keys, 1) != 1) {
debug2("%s: CA %s %s is not listed in %s", __func__,
key_type(key->cert->signature_key), ca_fp,
options.trusted_user_ca_keys);
goto out;
}
if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) {
error("%s", reason);
auth_debug_add("%s", reason);
goto out;
}
if (auth_cert_constraints(&key->cert->constraints, pw) != 0)
goto out;
verbose("%s certificate %s allowed by trusted %s key %s",
key_type(key), key_fp, key_type(key->cert->signature_key), ca_fp);
ret = 1;
out:
if (key_fp != NULL)
xfree(key_fp);
if (ca_fp != NULL)
xfree(ca_fp);
return ret;
}
/* check whether given key is in .ssh/authorized_keys* */ /* check whether given key is in .ssh/authorized_keys* */
int int
user_key_allowed(struct passwd *pw, Key *key) user_key_allowed(struct passwd *pw, Key *key)
@ -254,6 +325,15 @@ user_key_allowed(struct passwd *pw, Key *key)
int success; int success;
char *file; char *file;
if (auth_key_is_revoked(key))
return 0;
if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
return 0;
success = user_cert_trusted_ca(pw, key);
if (success)
return success;
file = authorized_keys_file(pw); file = authorized_keys_file(pw);
success = user_key_allowed2(pw, key, file); success = user_key_allowed2(pw, key, file);
xfree(file); xfree(file);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.c,v 1.80 2006/08/03 03:34:41 deraadt Exp $ */ /* $OpenBSD: authfd.c,v 1.82 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -483,6 +483,16 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
buffer_put_bignum2(b, key->rsa->p); buffer_put_bignum2(b, key->rsa->p);
buffer_put_bignum2(b, key->rsa->q); buffer_put_bignum2(b, key->rsa->q);
break; break;
case KEY_RSA_CERT:
if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
fatal("%s: no cert/certblob", __func__);
buffer_put_string(b, buffer_ptr(&key->cert->certblob),
buffer_len(&key->cert->certblob));
buffer_put_bignum2(b, key->rsa->d);
buffer_put_bignum2(b, key->rsa->iqmp);
buffer_put_bignum2(b, key->rsa->p);
buffer_put_bignum2(b, key->rsa->q);
break;
case KEY_DSA: case KEY_DSA:
buffer_put_bignum2(b, key->dsa->p); buffer_put_bignum2(b, key->dsa->p);
buffer_put_bignum2(b, key->dsa->q); buffer_put_bignum2(b, key->dsa->q);
@ -490,6 +500,13 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment)
buffer_put_bignum2(b, key->dsa->pub_key); buffer_put_bignum2(b, key->dsa->pub_key);
buffer_put_bignum2(b, key->dsa->priv_key); buffer_put_bignum2(b, key->dsa->priv_key);
break; break;
case KEY_DSA_CERT:
if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
fatal("%s: no cert/certblob", __func__);
buffer_put_string(b, buffer_ptr(&key->cert->certblob),
buffer_len(&key->cert->certblob));
buffer_put_bignum2(b, key->dsa->priv_key);
break;
} }
buffer_put_cstring(b, comment); buffer_put_cstring(b, comment);
} }
@ -517,7 +534,9 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
ssh_encode_identity_rsa1(&msg, key->rsa, comment); ssh_encode_identity_rsa1(&msg, key->rsa, comment);
break; break;
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
type = constrained ? type = constrained ?
SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_ID_CONSTRAINED :
SSH2_AGENTC_ADD_IDENTITY; SSH2_AGENTC_ADD_IDENTITY;
@ -545,12 +564,6 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key,
return decode_reply(type); return decode_reply(type);
} }
int
ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
{
return ssh_add_identity_constrained(auth, key, comment, 0, 0);
}
/* /*
* Removes an identity from the authentication server. This call is not * Removes an identity from the authentication server. This call is not
* meant to be used by normal applications. * meant to be used by normal applications.
@ -571,7 +584,8 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key)
buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_int(&msg, BN_num_bits(key->rsa->n));
buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->e);
buffer_put_bignum(&msg, key->rsa->n); buffer_put_bignum(&msg, key->rsa->n);
} else if (key->type == KEY_DSA || key->type == KEY_RSA) { } else if (key_type_plain(key->type) == KEY_DSA ||
key_type_plain(key->type) == KEY_RSA) {
key_to_blob(key, &blob, &blen); key_to_blob(key, &blob, &blen);
buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, blob, blen);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfd.h,v 1.36 2006/08/03 03:34:41 deraadt Exp $ */ /* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -75,7 +75,6 @@ void ssh_close_authentication_connection(AuthenticationConnection *);
int ssh_get_num_identities(AuthenticationConnection *, int); int ssh_get_num_identities(AuthenticationConnection *, int);
Key *ssh_get_first_identity(AuthenticationConnection *, char **, int); Key *ssh_get_first_identity(AuthenticationConnection *, char **, int);
Key *ssh_get_next_identity(AuthenticationConnection *, char **, int); Key *ssh_get_next_identity(AuthenticationConnection *, char **, int);
int ssh_add_identity(AuthenticationConnection *, Key *, const char *);
int ssh_add_identity_constrained(AuthenticationConnection *, Key *, int ssh_add_identity_constrained(AuthenticationConnection *, Key *,
const char *, u_int, u_int); const char *, u_int, u_int);
int ssh_remove_identity(AuthenticationConnection *, Key *); int ssh_remove_identity(AuthenticationConnection *, Key *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.c,v 1.76 2006/08/03 03:34:41 deraadt Exp $ */ /* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -47,6 +47,9 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/pem.h> #include <openssl/pem.h>
/* compatibility with old or broken OpenSSL versions */
#include "openbsd-compat/openssl-compat.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h> #include <stdarg.h>
@ -184,7 +187,11 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
int success = 0; int success = 0;
int len = strlen(_passphrase); int len = strlen(_passphrase);
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
#else
const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
#endif
if (len > 0 && len <= 4) { if (len > 0 && len <= 4) {
error("passphrase too short: have %d bytes, need > 4", len); error("passphrase too short: have %d bytes, need > 4", len);
@ -552,8 +559,13 @@ key_load_private_type(int type, const char *filename, const char *passphrase,
int fd; int fd;
fd = open(filename, O_RDONLY); fd = open(filename, O_RDONLY);
if (fd < 0) if (fd < 0) {
debug("could not open key file '%s': %s", filename,
strerror(errno));
if (perm_ok != NULL)
*perm_ok = 0;
return NULL; return NULL;
}
if (!key_perm_ok(fd, filename)) { if (!key_perm_ok(fd, filename)) {
if (perm_ok != NULL) if (perm_ok != NULL)
*perm_ok = 0; *perm_ok = 0;
@ -588,8 +600,11 @@ key_load_private(const char *filename, const char *passphrase,
int fd; int fd;
fd = open(filename, O_RDONLY); fd = open(filename, O_RDONLY);
if (fd < 0) if (fd < 0) {
debug("could not open key file '%s': %s", filename,
strerror(errno));
return NULL; return NULL;
}
if (!key_perm_ok(fd, filename)) { if (!key_perm_ok(fd, filename)) {
error("bad permissions: ignore key: %s", filename); error("bad permissions: ignore key: %s", filename);
close(fd); close(fd);
@ -677,3 +692,65 @@ key_load_public(const char *filename, char **commentp)
key_free(pub); key_free(pub);
return NULL; return NULL;
} }
/*
* Returns 1 if the specified "key" is listed in the file "filename",
* 0 if the key is not listed or -1 on error.
* If strict_type is set then the key type must match exactly,
* otherwise a comparison that ignores certficiate data is performed.
*/
int
key_in_file(Key *key, const char *filename, int strict_type)
{
FILE *f;
char line[SSH_MAX_PUBKEY_BYTES];
char *cp;
u_long linenum = 0;
int ret = 0;
Key *pub;
int (*key_compare)(const Key *, const Key *) = strict_type ?
key_equal : key_equal_public;
if ((f = fopen(filename, "r")) == NULL) {
if (errno == ENOENT) {
debug("%s: keyfile \"%s\" missing", __func__, filename);
return 0;
} else {
error("%s: could not open keyfile \"%s\": %s", __func__,
filename, strerror(errno));
return -1;
}
}
while (read_keyfile_line(f, filename, line, sizeof(line),
&linenum) != -1) {
cp = line;
/* Skip leading whitespace. */
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
/* Skip comments and empty lines */
switch (*cp) {
case '#':
case '\n':
case '\0':
continue;
}
pub = key_new(KEY_UNSPEC);
if (key_read(pub, &cp) != 1) {
key_free(pub);
continue;
}
if (key_compare(key, pub)) {
ret = 1;
key_free(pub);
break;
}
key_free(pub);
}
fclose(f);
return ret;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.h,v 1.13 2006/04/25 08:02:27 dtucker Exp $ */ /* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -22,5 +22,6 @@ Key *key_load_private(const char *, const char *, char **);
Key *key_load_private_type(int, const char *, const char *, char **, int *); Key *key_load_private_type(int, const char *, const char *, char **, int *);
Key *key_load_private_pem(int, int, const char *, char **); Key *key_load_private_pem(int, int, const char *, char **);
int key_perm_ok(int, const char *); int key_perm_ok(int, const char *);
int key_in_file(Key *, const char *, int);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: bufaux.c,v 1.46 2008/06/10 23:21:34 dtucker Exp $ */ /* $OpenBSD: bufaux.c,v 1.48 2010/02/02 22:49:34 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -166,7 +166,10 @@ buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
u_int len; u_int len;
/* Get the length. */ /* Get the length. */
len = buffer_get_int(buffer); if (buffer_get_int_ret(&len, buffer) != 0) {
error("buffer_get_string_ret: cannot extract length");
return (NULL);
}
if (len > 256 * 1024) { if (len > 256 * 1024) {
error("buffer_get_string_ret: bad string length %u", len); error("buffer_get_string_ret: bad string length %u", len);
return (NULL); return (NULL);
@ -198,14 +201,17 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr)
} }
void * void *
buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr)
{ {
void *ptr; void *ptr;
u_int len; u_int len;
len = buffer_get_int(buffer); if (buffer_get_int_ret(&len, buffer) != 0)
if (len > 256 * 1024) return NULL;
fatal("buffer_get_string_ptr: bad string length %u", len); if (len > 256 * 1024) {
error("buffer_get_string_ptr: bad string length %u", len);
return NULL;
}
ptr = buffer_ptr(buffer); ptr = buffer_ptr(buffer);
buffer_consume(buffer, len); buffer_consume(buffer, len);
if (length_ptr) if (length_ptr)
@ -213,6 +219,16 @@ buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
return (ptr); return (ptr);
} }
void *
buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
{
void *ret;
if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL)
fatal("buffer_get_string_ptr: buffer error");
return (ret);
}
/* /*
* Stores and arbitrary binary string in the buffer. * Stores and arbitrary binary string in the buffer.
*/ */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt Exp $ */ /* $OpenBSD: buffer.c,v 1.32 2010/02/09 03:56:28 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -160,7 +160,7 @@ buffer_check_alloc(Buffer *buffer, u_int len)
/* Returns the number of bytes of data in the buffer. */ /* Returns the number of bytes of data in the buffer. */
u_int u_int
buffer_len(Buffer *buffer) buffer_len(const Buffer *buffer)
{ {
return buffer->end - buffer->offset; return buffer->end - buffer->offset;
} }
@ -228,7 +228,7 @@ buffer_consume_end(Buffer *buffer, u_int bytes)
/* Returns a pointer to the first used byte in the buffer. */ /* Returns a pointer to the first used byte in the buffer. */
void * void *
buffer_ptr(Buffer *buffer) buffer_ptr(const Buffer *buffer)
{ {
return buffer->buf + buffer->offset; return buffer->buf + buffer->offset;
} }
@ -236,7 +236,7 @@ buffer_ptr(Buffer *buffer)
/* Dumps the contents of the buffer to stderr. */ /* Dumps the contents of the buffer to stderr. */
void void
buffer_dump(Buffer *buffer) buffer_dump(const Buffer *buffer)
{ {
u_int i; u_int i;
u_char *ucp = buffer->buf; u_char *ucp = buffer->buf;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: buffer.h,v 1.17 2008/05/08 06:59:01 markus Exp $ */ /* $OpenBSD: buffer.h,v 1.19 2010/02/09 03:56:28 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -27,8 +27,8 @@ void buffer_init(Buffer *);
void buffer_clear(Buffer *); void buffer_clear(Buffer *);
void buffer_free(Buffer *); void buffer_free(Buffer *);
u_int buffer_len(Buffer *); u_int buffer_len(const Buffer *);
void *buffer_ptr(Buffer *); void *buffer_ptr(const Buffer *);
void buffer_append(Buffer *, const void *, u_int); void buffer_append(Buffer *, const void *, u_int);
void *buffer_append_space(Buffer *, u_int); void *buffer_append_space(Buffer *, u_int);
@ -40,7 +40,7 @@ void buffer_get(Buffer *, void *, u_int);
void buffer_consume(Buffer *, u_int); void buffer_consume(Buffer *, u_int);
void buffer_consume_end(Buffer *, u_int); void buffer_consume_end(Buffer *, u_int);
void buffer_dump(Buffer *); void buffer_dump(const Buffer *);
int buffer_get_ret(Buffer *, void *, u_int); int buffer_get_ret(Buffer *, void *, u_int);
int buffer_consume_ret(Buffer *, u_int); int buffer_consume_ret(Buffer *, u_int);
@ -81,6 +81,7 @@ int buffer_get_short_ret(u_short *, Buffer *);
int buffer_get_int_ret(u_int *, Buffer *); int buffer_get_int_ret(u_int *, Buffer *);
int buffer_get_int64_ret(u_int64_t *, Buffer *); int buffer_get_int64_ret(u_int64_t *, Buffer *);
void *buffer_get_string_ret(Buffer *, u_int *); void *buffer_get_string_ret(Buffer *, u_int *);
void *buffer_get_string_ptr_ret(Buffer *, u_int *);
int buffer_get_char_ret(char *, Buffer *); int buffer_get_char_ret(char *, Buffer *);
#endif /* BUFFER_H */ #endif /* BUFFER_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: canohost.c,v 1.65 2009/05/27 06:31:25 andreas Exp $ */ /* $OpenBSD: canohost.c,v 1.66 2010/01/13 01:20:20 dtucker Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -27,6 +27,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <unistd.h>
#include "xmalloc.h" #include "xmalloc.h"
#include "packet.h" #include "packet.h"
@ -301,9 +302,22 @@ get_local_ipaddr(int sock)
} }
char * char *
get_local_name(int sock) get_local_name(int fd)
{ {
return get_socket_address(sock, 0, NI_NAMEREQD); char *host, myname[NI_MAXHOST];
/* Assume we were passed a socket */
if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL)
return host;
/* Handle the case where we were passed a pipe */
if (gethostname(myname, sizeof(myname)) == -1) {
verbose("get_local_name: gethostname: %s", strerror(errno));
} else {
host = xstrdup(myname);
}
return host;
} }
void void

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.296 2009/05/25 06:48:00 andreas Exp $ */ /* $OpenBSD: channels.c,v 1.303 2010/01/30 21:12:08 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -53,6 +53,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <netdb.h> #include <netdb.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -228,12 +229,16 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
channel_max_fd = MAX(channel_max_fd, wfd); channel_max_fd = MAX(channel_max_fd, wfd);
channel_max_fd = MAX(channel_max_fd, efd); channel_max_fd = MAX(channel_max_fd, efd);
/* XXX set close-on-exec -markus */ if (rfd != -1)
fcntl(rfd, F_SETFD, FD_CLOEXEC);
if (wfd != -1 && wfd != rfd)
fcntl(wfd, F_SETFD, FD_CLOEXEC);
if (efd != -1 && efd != rfd && efd != wfd)
fcntl(efd, F_SETFD, FD_CLOEXEC);
c->rfd = rfd; c->rfd = rfd;
c->wfd = wfd; c->wfd = wfd;
c->sock = (rfd == wfd) ? rfd : -1; c->sock = (rfd == wfd) ? rfd : -1;
c->ctl_fd = -1; /* XXX: set elsewhere */
c->efd = efd; c->efd = efd;
c->extended_usage = extusage; c->extended_usage = extusage;
@ -322,6 +327,10 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
c->output_filter = NULL; c->output_filter = NULL;
c->filter_ctx = NULL; c->filter_ctx = NULL;
c->filter_cleanup = NULL; c->filter_cleanup = NULL;
c->ctl_chan = -1;
c->mux_rcb = NULL;
c->mux_ctx = NULL;
c->delayed = 1; /* prevent call to channel_post handler */
TAILQ_INIT(&c->status_confirms); TAILQ_INIT(&c->status_confirms);
debug("channel %d: new [%s]", found, remote_name); debug("channel %d: new [%s]", found, remote_name);
return c; return c;
@ -363,11 +372,10 @@ channel_close_fd(int *fdp)
static void static void
channel_close_fds(Channel *c) channel_close_fds(Channel *c)
{ {
debug3("channel %d: close_fds r %d w %d e %d c %d", debug3("channel %d: close_fds r %d w %d e %d",
c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); c->self, c->rfd, c->wfd, c->efd);
channel_close_fd(&c->sock); channel_close_fd(&c->sock);
channel_close_fd(&c->ctl_fd);
channel_close_fd(&c->rfd); channel_close_fd(&c->rfd);
channel_close_fd(&c->wfd); channel_close_fd(&c->wfd);
channel_close_fd(&c->efd); channel_close_fd(&c->efd);
@ -393,8 +401,6 @@ channel_free(Channel *c)
if (c->sock != -1) if (c->sock != -1)
shutdown(c->sock, SHUT_RDWR); shutdown(c->sock, SHUT_RDWR);
if (c->ctl_fd != -1)
shutdown(c->ctl_fd, SHUT_RDWR);
channel_close_fds(c); channel_close_fds(c);
buffer_free(&c->input); buffer_free(&c->input);
buffer_free(&c->output); buffer_free(&c->output);
@ -516,6 +522,7 @@ channel_still_open(void)
case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_PORT_LISTENER: case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_MUX_LISTENER:
case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_AUTH_SOCKET:
case SSH_CHANNEL_DYNAMIC: case SSH_CHANNEL_DYNAMIC:
@ -529,6 +536,7 @@ channel_still_open(void)
case SSH_CHANNEL_OPENING: case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_OPEN: case SSH_CHANNEL_OPEN:
case SSH_CHANNEL_X11_OPEN: case SSH_CHANNEL_X11_OPEN:
case SSH_CHANNEL_MUX_CLIENT:
return 1; return 1;
case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_INPUT_DRAINING:
case SSH_CHANNEL_OUTPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING:
@ -560,6 +568,8 @@ channel_find_open(void)
case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_X11_LISTENER:
case SSH_CHANNEL_PORT_LISTENER: case SSH_CHANNEL_PORT_LISTENER:
case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_RPORT_LISTENER:
case SSH_CHANNEL_MUX_LISTENER:
case SSH_CHANNEL_MUX_CLIENT:
case SSH_CHANNEL_OPENING: case SSH_CHANNEL_OPENING:
case SSH_CHANNEL_CONNECTING: case SSH_CHANNEL_CONNECTING:
case SSH_CHANNEL_ZOMBIE: case SSH_CHANNEL_ZOMBIE:
@ -610,6 +620,8 @@ channel_open_message(void)
case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_CLOSED:
case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_AUTH_SOCKET:
case SSH_CHANNEL_ZOMBIE: case SSH_CHANNEL_ZOMBIE:
case SSH_CHANNEL_MUX_CLIENT:
case SSH_CHANNEL_MUX_LISTENER:
continue; continue;
case SSH_CHANNEL_LARVAL: case SSH_CHANNEL_LARVAL:
case SSH_CHANNEL_OPENING: case SSH_CHANNEL_OPENING:
@ -620,12 +632,12 @@ channel_open_message(void)
case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_INPUT_DRAINING:
case SSH_CHANNEL_OUTPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING:
snprintf(buf, sizeof buf, snprintf(buf, sizeof buf,
" #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cc %d)\r\n",
c->self, c->remote_name, c->self, c->remote_name,
c->type, c->remote_id, c->type, c->remote_id,
c->istate, buffer_len(&c->input), c->istate, buffer_len(&c->input),
c->ostate, buffer_len(&c->output), c->ostate, buffer_len(&c->output),
c->rfd, c->wfd, c->ctl_fd); c->rfd, c->wfd, c->ctl_chan);
buffer_append(&buffer, buf, strlen(buf)); buffer_append(&buffer, buf, strlen(buf));
continue; continue;
default: default:
@ -832,9 +844,6 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
FD_SET(c->efd, readset); FD_SET(c->efd, readset);
} }
/* XXX: What about efd? races? */ /* XXX: What about efd? races? */
if (compat20 && c->ctl_fd != -1 &&
c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN)
FD_SET(c->ctl_fd, readset);
} }
/* ARGSUSED */ /* ARGSUSED */
@ -979,6 +988,28 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
} }
} }
static void
channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
{
if (c->istate == CHAN_INPUT_OPEN &&
buffer_check_alloc(&c->input, CHAN_RBUF))
FD_SET(c->rfd, readset);
if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
/* clear buffer immediately (discard any partial packet) */
buffer_clear(&c->input);
chan_ibuf_empty(c);
/* Start output drain. XXX just kill chan? */
chan_rcvd_oclose(c);
}
if (c->ostate == CHAN_OUTPUT_OPEN ||
c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
if (buffer_len(&c->output) > 0)
FD_SET(c->wfd, writeset);
else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
chan_obuf_empty(c);
}
}
/* try to decode a socks4 header */ /* try to decode a socks4 header */
/* ARGSUSED */ /* ARGSUSED */
static int static int
@ -1210,6 +1241,30 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
return 1; return 1;
} }
Channel *
channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
int in, int out)
{
Channel *c;
debug("channel_connect_stdio_fwd %s:%d", host_to_connect,
port_to_connect);
c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out,
-1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
0, "stdio-forward", /*nonblock*/0);
c->path = xstrdup(host_to_connect);
c->host_port = port_to_connect;
c->listening_port = 0;
c->force_drain = 1;
channel_register_fds(c, in, out, -1, 0, 1, 0);
port_open_helper(c, "direct-tcpip");
return c;
}
/* dynamic port forwarding */ /* dynamic port forwarding */
static void static void
channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
@ -1219,7 +1274,6 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
int ret; int ret;
have = buffer_len(&c->input); have = buffer_len(&c->input);
c->delayed = 0;
debug2("channel %d: pre_dynamic: have %d", c->self, have); debug2("channel %d: pre_dynamic: have %d", c->self, have);
/* buffer_dump(&c->input); */ /* buffer_dump(&c->input); */
/* check if the fixed size part of the packet is in buffer. */ /* check if the fixed size part of the packet is in buffer. */
@ -1322,6 +1376,13 @@ port_open_helper(Channel *c, char *rtype)
char *remote_ipaddr = get_peer_ipaddr(c->sock); char *remote_ipaddr = get_peer_ipaddr(c->sock);
int remote_port = get_peer_port(c->sock); int remote_port = get_peer_port(c->sock);
if (remote_port == -1) {
/* Fake addr/port to appease peers that validate it (Tectia) */
xfree(remote_ipaddr);
remote_ipaddr = xstrdup("127.0.0.1");
remote_port = 65535;
}
direct = (strcmp(rtype, "direct-tcpip") == 0); direct = (strcmp(rtype, "direct-tcpip") == 0);
snprintf(buf, sizeof buf, snprintf(buf, sizeof buf,
@ -1423,16 +1484,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
if (c->path != NULL) if (c->path != NULL)
nc->path = xstrdup(c->path); nc->path = xstrdup(c->path);
if (nextstate == SSH_CHANNEL_DYNAMIC) { if (nextstate != SSH_CHANNEL_DYNAMIC)
/*
* do not call the channel_post handler until
* this flag has been reset by a pre-handler.
* otherwise the FD_ISSET calls might overflow
*/
nc->delayed = 1;
} else {
port_open_helper(nc, rtype); port_open_helper(nc, rtype);
}
} }
} }
@ -1722,36 +1775,6 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
return 1; return 1;
} }
/* ARGSUSED */
static int
channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
{
char buf[16];
int len;
/* Monitor control fd to detect if the slave client exits */
if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
len = read(c->ctl_fd, buf, sizeof(buf));
if (len < 0 &&
(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
return 1;
if (len <= 0) {
debug2("channel %d: ctl read<=0", c->self);
if (c->type != SSH_CHANNEL_OPEN) {
debug2("channel %d: not open", c->self);
chan_mark_dead(c);
return -1;
} else {
chan_read_failed(c);
chan_write_failed(c);
}
return -1;
} else
fatal("%s: unexpected data on ctl fd", __func__);
}
return 1;
}
static int static int
channel_check_window(Channel *c) channel_check_window(Channel *c)
{ {
@ -1777,17 +1800,136 @@ channel_check_window(Channel *c)
static void static void
channel_post_open(Channel *c, fd_set *readset, fd_set *writeset) channel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
{ {
if (c->delayed)
return;
channel_handle_rfd(c, readset, writeset); channel_handle_rfd(c, readset, writeset);
channel_handle_wfd(c, readset, writeset); channel_handle_wfd(c, readset, writeset);
if (!compat20) if (!compat20)
return; return;
channel_handle_efd(c, readset, writeset); channel_handle_efd(c, readset, writeset);
channel_handle_ctl(c, readset, writeset);
channel_check_window(c); channel_check_window(c);
} }
static u_int
read_mux(Channel *c, u_int need)
{
char buf[CHAN_RBUF];
int len;
u_int rlen;
if (buffer_len(&c->input) < need) {
rlen = need - buffer_len(&c->input);
len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF));
if (len <= 0) {
if (errno != EINTR && errno != EAGAIN) {
debug2("channel %d: ctl read<=0 rfd %d len %d",
c->self, c->rfd, len);
chan_read_failed(c);
return 0;
}
} else
buffer_append(&c->input, buf, len);
}
return buffer_len(&c->input);
}
static void
channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
{
u_int need;
ssize_t len;
if (!compat20)
fatal("%s: entered with !compat20", __func__);
if (c->rfd != -1 && FD_ISSET(c->rfd, readset) &&
(c->istate == CHAN_INPUT_OPEN ||
c->istate == CHAN_INPUT_WAIT_DRAIN)) {
/*
* Don't not read past the precise end of packets to
* avoid disrupting fd passing.
*/
if (read_mux(c, 4) < 4) /* read header */
return;
need = get_u32(buffer_ptr(&c->input));
#define CHANNEL_MUX_MAX_PACKET (256 * 1024)
if (need > CHANNEL_MUX_MAX_PACKET) {
debug2("channel %d: packet too big %u > %u",
c->self, CHANNEL_MUX_MAX_PACKET, need);
chan_rcvd_oclose(c);
return;
}
if (read_mux(c, need + 4) < need + 4) /* read body */
return;
if (c->mux_rcb(c) != 0) {
debug("channel %d: mux_rcb failed", c->self);
chan_mark_dead(c);
return;
}
}
if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) &&
buffer_len(&c->output) > 0) {
len = write(c->wfd, buffer_ptr(&c->output),
buffer_len(&c->output));
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return;
if (len <= 0) {
chan_mark_dead(c);
return;
}
buffer_consume(&c->output, len);
}
}
static void
channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
{
Channel *nc;
struct sockaddr_storage addr;
socklen_t addrlen;
int newsock;
uid_t euid;
gid_t egid;
if (!FD_ISSET(c->sock, readset))
return;
debug("multiplexing control connection");
/*
* Accept connection on control socket
*/
memset(&addr, 0, sizeof(addr));
addrlen = sizeof(addr);
if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
&addrlen)) == -1) {
error("%s accept: %s", __func__, strerror(errno));
return;
}
if (getpeereid(newsock, &euid, &egid) < 0) {
error("%s getpeereid failed: %s", __func__,
strerror(errno));
close(newsock);
return;
}
if ((euid != 0) && (getuid() != euid)) {
error("multiplex uid mismatch: peer euid %u != uid %u",
(u_int)euid, (u_int)getuid());
close(newsock);
return;
}
nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT,
newsock, newsock, -1, c->local_window_max,
c->local_maxpacket, 0, "mux-control", 1);
nc->mux_rcb = c->mux_rcb;
debug3("%s: new mux channel %d fd %d", __func__,
nc->self, nc->sock);
/* establish state */
nc->mux_rcb(nc);
/* mux state transitions must not elicit protocol messages */
nc->flags |= CHAN_LOCAL;
}
/* ARGSUSED */ /* ARGSUSED */
static void static void
channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
@ -1816,6 +1958,8 @@ channel_handler_init_20(void)
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener;
channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client;
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
@ -1824,6 +1968,8 @@ channel_handler_init_20(void)
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener;
channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client;
} }
static void static void
@ -1910,17 +2056,23 @@ static void
channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset)
{ {
static int did_init = 0; static int did_init = 0;
u_int i; u_int i, oalloc;
Channel *c; Channel *c;
if (!did_init) { if (!did_init) {
channel_handler_init(); channel_handler_init();
did_init = 1; did_init = 1;
} }
for (i = 0; i < channels_alloc; i++) { for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
c = channels[i]; c = channels[i];
if (c == NULL) if (c == NULL)
continue; continue;
if (c->delayed) {
if (ftab == channel_pre)
c->delayed = 0;
else
continue;
}
if (ftab[c->type] != NULL) if (ftab[c->type] != NULL)
(*ftab[c->type])(c, readset, writeset); (*ftab[c->type])(c, readset, writeset);
channel_garbage_collect(c); channel_garbage_collect(c);
@ -2577,6 +2729,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
} }
channel_set_reuseaddr(sock); channel_set_reuseaddr(sock);
if (ai->ai_family == AF_INET6)
sock_set_v6only(sock);
debug("Local forwarding listening on %s port %s.", debug("Local forwarding listening on %s port %s.",
ntop, strport); ntop, strport);
@ -3108,13 +3262,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
continue; continue;
} }
} }
#ifdef IPV6_V6ONLY if (ai->ai_family == AF_INET6)
if (ai->ai_family == AF_INET6) { sock_set_v6only(sock);
int on = 1;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
}
#endif
if (x11_use_localhost) if (x11_use_localhost)
channel_set_reuseaddr(sock); channel_set_reuseaddr(sock);
if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.h,v 1.98 2009/02/12 03:00:56 djm Exp $ */ /* $OpenBSD: channels.h,v 1.103 2010/01/26 01:28:35 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -53,7 +53,9 @@
#define SSH_CHANNEL_CONNECTING 12 #define SSH_CHANNEL_CONNECTING 12
#define SSH_CHANNEL_DYNAMIC 13 #define SSH_CHANNEL_DYNAMIC 13
#define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */ #define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */
#define SSH_CHANNEL_MAX_TYPE 15 #define SSH_CHANNEL_MUX_LISTENER 15 /* Listener for mux conn. */
#define SSH_CHANNEL_MUX_CLIENT 16 /* Conn. to mux slave */
#define SSH_CHANNEL_MAX_TYPE 17
struct Channel; struct Channel;
typedef struct Channel Channel; typedef struct Channel Channel;
@ -81,6 +83,9 @@ struct channel_connect {
struct addrinfo *ai, *aitop; struct addrinfo *ai, *aitop;
}; };
/* Callbacks for mux channels back into client-specific code */
typedef int mux_callback_fn(struct Channel *);
struct Channel { struct Channel {
int type; /* channel type/state */ int type; /* channel type/state */
int self; /* my own channel identifier */ int self; /* my own channel identifier */
@ -92,12 +97,16 @@ struct Channel {
int wfd; /* write fd */ int wfd; /* write fd */
int efd; /* extended fd */ int efd; /* extended fd */
int sock; /* sock fd */ int sock; /* sock fd */
int ctl_fd; /* control fd (client sharing) */ int ctl_chan; /* control channel (multiplexed connections) */
int isatty; /* rfd is a tty */ int isatty; /* rfd is a tty */
int wfd_isatty; /* wfd is a tty */ int wfd_isatty; /* wfd is a tty */
int client_tty; /* (client) TTY has been requested */ int client_tty; /* (client) TTY has been requested */
int force_drain; /* force close on iEOF */ int force_drain; /* force close on iEOF */
int delayed; /* fdset hack */ int delayed; /* post-select handlers for newly created
* channels are delayed until the first call
* to a matching pre-select handler.
* this way post-select handlers are not
* accidenly called if a FD gets reused */
Buffer input; /* data read from socket, to be sent over Buffer input; /* data read from socket, to be sent over
* encrypted connection */ * encrypted connection */
Buffer output; /* data received over encrypted connection for Buffer output; /* data received over encrypted connection for
@ -138,6 +147,10 @@ struct Channel {
/* non-blocking connect */ /* non-blocking connect */
struct channel_connect connect_ctx; struct channel_connect connect_ctx;
/* multiplexing protocol hook, called for each packet received */
mux_callback_fn *mux_rcb;
void *mux_ctx;
}; };
#define CHAN_EXTENDED_IGNORE 0 #define CHAN_EXTENDED_IGNORE 0
@ -168,6 +181,7 @@ struct Channel {
#define CHAN_CLOSE_RCVD 0x02 #define CHAN_CLOSE_RCVD 0x02
#define CHAN_EOF_SENT 0x04 #define CHAN_EOF_SENT 0x04
#define CHAN_EOF_RCVD 0x08 #define CHAN_EOF_RCVD 0x08
#define CHAN_LOCAL 0x10
#define CHAN_RBUF 16*1024 #define CHAN_RBUF 16*1024
@ -239,6 +253,7 @@ void channel_clear_adm_permitted_opens(void);
void channel_print_adm_permitted_opens(void); void channel_print_adm_permitted_opens(void);
int channel_input_port_forward_request(int, int); int channel_input_port_forward_request(int, int);
Channel *channel_connect_to(const char *, u_short, char *, char *); Channel *channel_connect_to(const char *, u_short, char *, char *);
Channel *channel_connect_stdio_fwd(const char*, u_short, int, int);
Channel *channel_connect_by_listen_address(u_short, char *, char *); Channel *channel_connect_by_listen_address(u_short, char *, char *);
int channel_request_remote_forwarding(const char *, u_short, int channel_request_remote_forwarding(const char *, u_short,
const char *, u_short); const char *, u_short);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.213 2009/07/05 19:28:33 stevesk Exp $ */ /* $OpenBSD: clientloop.c,v 1.218 2010/01/28 00:21:18 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -121,7 +121,7 @@ extern int stdin_null_flag;
extern int no_shell_flag; extern int no_shell_flag;
/* Control socket */ /* Control socket */
extern int muxserver_sock; extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */
/* /*
* Name of the host we are connecting to. This is the name given on the * Name of the host we are connecting to. This is the name given on the
@ -130,6 +130,9 @@ extern int muxserver_sock;
*/ */
extern char *host; extern char *host;
/* Force TTY allocation */
extern int force_tty_flag;
/* /*
* Flag to indicate that we have received a window change signal which has * 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 * not yet been processed. This will cause a message indicating the new
@ -143,7 +146,7 @@ static volatile sig_atomic_t received_signal = 0;
static int in_non_blocking_mode = 0; static int in_non_blocking_mode = 0;
/* Common data for the client loop code. */ /* Common data for the client loop code. */
static volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */ volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
static int escape_char1; /* Escape character. (proto1 only) */ static int escape_char1; /* Escape character. (proto1 only) */
static int escape_pending1; /* Last character was an escape (proto1 only) */ static int escape_pending1; /* Last character was an escape (proto1 only) */
static int last_was_cr; /* Last character was a newline. */ static int last_was_cr; /* Last character was a newline. */
@ -161,6 +164,8 @@ static int session_closed = 0; /* In SSH2: login session closed. */
static void client_init_dispatch(void); static void client_init_dispatch(void);
int session_ident = -1; int session_ident = -1;
int session_resumed = 0;
/* Track escape per proto2 channel */ /* Track escape per proto2 channel */
struct escape_filter_ctx { struct escape_filter_ctx {
int escape_pending; int escape_pending;
@ -559,9 +564,6 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
if (packet_have_data_to_write()) if (packet_have_data_to_write())
FD_SET(connection_out, *writesetp); FD_SET(connection_out, *writesetp);
if (muxserver_sock != -1)
FD_SET(muxserver_sock, *readsetp);
/* /*
* Wait for something to happen. This will suspend the process until * Wait for something to happen. This will suspend the process until
* some selected descriptor can be read, written, or has some other * some selected descriptor can be read, written, or has some other
@ -608,7 +610,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
atomicio(vwrite, fileno(stderr), buffer_ptr(berr), atomicio(vwrite, fileno(stderr), buffer_ptr(berr),
buffer_len(berr)); buffer_len(berr));
leave_raw_mode(); leave_raw_mode(force_tty_flag);
/* /*
* Free (and clear) the buffer to reduce the amount of data that gets * Free (and clear) the buffer to reduce the amount of data that gets
@ -629,7 +631,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
buffer_init(bout); buffer_init(bout);
buffer_init(berr); buffer_init(berr);
enter_raw_mode(); enter_raw_mode(force_tty_flag);
} }
static void static void
@ -690,7 +692,7 @@ client_status_confirm(int type, Channel *c, void *ctx)
/* XXX supress on mux _client_ quietmode */ /* XXX supress on mux _client_ quietmode */
tochan = options.log_level >= SYSLOG_LEVEL_ERROR && tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
if (type == SSH2_MSG_CHANNEL_SUCCESS) { if (type == SSH2_MSG_CHANNEL_SUCCESS) {
debug2("%s request accepted on channel %d", debug2("%s request accepted on channel %d",
@ -772,7 +774,7 @@ process_cmdline(void)
bzero(&fwd, sizeof(fwd)); bzero(&fwd, sizeof(fwd));
fwd.listen_host = fwd.connect_host = NULL; fwd.listen_host = fwd.connect_host = NULL;
leave_raw_mode(); leave_raw_mode(force_tty_flag);
handler = signal(SIGINT, SIG_IGN); handler = signal(SIGINT, SIG_IGN);
cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); cmd = s = read_passphrase("\r\nssh> ", RP_ECHO);
if (s == NULL) if (s == NULL)
@ -834,6 +836,7 @@ process_cmdline(void)
while (isspace(*++s)) while (isspace(*++s))
; ;
/* XXX update list of forwards in options */
if (delete) { if (delete) {
cancel_port = 0; cancel_port = 0;
cancel_host = hpdelim(&s); /* may be NULL */ cancel_host = hpdelim(&s); /* may be NULL */
@ -875,7 +878,7 @@ process_cmdline(void)
out: out:
signal(SIGINT, handler); signal(SIGINT, handler);
enter_raw_mode(); enter_raw_mode(force_tty_flag);
if (cmd) if (cmd)
xfree(cmd); xfree(cmd);
if (fwd.listen_host != NULL) if (fwd.listen_host != NULL)
@ -931,7 +934,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
escape_char); escape_char);
buffer_append(berr, string, strlen(string)); buffer_append(berr, string, strlen(string));
if (c && c->ctl_fd != -1) { if (c && c->ctl_chan != -1) {
chan_read_failed(c); chan_read_failed(c);
chan_write_failed(c); chan_write_failed(c);
return 0; return 0;
@ -941,7 +944,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
case 'Z' - 64: case 'Z' - 64:
/* XXX support this for mux clients */ /* XXX support this for mux clients */
if (c && c->ctl_fd != -1) { if (c && c->ctl_chan != -1) {
noescape: noescape:
snprintf(string, sizeof string, snprintf(string, sizeof string,
"%c%c escape not available to " "%c%c escape not available to "
@ -986,7 +989,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
continue; continue;
case '&': case '&':
if (c && c->ctl_fd != -1) if (c && c->ctl_chan != -1)
goto noescape; goto noescape;
/* /*
* Detach the program (continue to serve * Detach the program (continue to serve
@ -994,7 +997,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
* more new connections). * more new connections).
*/ */
/* Restore tty modes. */ /* Restore tty modes. */
leave_raw_mode(); leave_raw_mode(force_tty_flag);
/* Stop listening for new connections. */ /* Stop listening for new connections. */
channel_stop_listening(); channel_stop_listening();
@ -1037,7 +1040,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
continue; continue;
case '?': case '?':
if (c && c->ctl_fd != -1) { if (c && c->ctl_chan != -1) {
snprintf(string, sizeof string, snprintf(string, sizeof string,
"%c?\r\n\ "%c?\r\n\
Supported escape sequences:\r\n\ Supported escape sequences:\r\n\
@ -1086,7 +1089,7 @@ Supported escape sequences:\r\n\
continue; continue;
case 'C': case 'C':
if (c && c->ctl_fd != -1) if (c && c->ctl_chan != -1)
goto noescape; goto noescape;
process_cmdline(); process_cmdline();
continue; continue;
@ -1289,7 +1292,7 @@ client_channel_closed(int id, void *arg)
{ {
channel_cancel_cleanup(id); channel_cancel_cleanup(id);
session_closed = 1; session_closed = 1;
leave_raw_mode(); leave_raw_mode(force_tty_flag);
} }
/* /*
@ -1322,8 +1325,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
connection_in = packet_get_connection_in(); connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out(); connection_out = packet_get_connection_out();
max_fd = MAX(connection_in, connection_out); max_fd = MAX(connection_in, connection_out);
if (muxserver_sock != -1)
max_fd = MAX(max_fd, muxserver_sock);
if (!compat20) { if (!compat20) {
/* enable nonblocking unless tty */ /* enable nonblocking unless tty */
@ -1362,7 +1363,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
signal(SIGWINCH, window_change_handler); signal(SIGWINCH, window_change_handler);
if (have_pty) if (have_pty)
enter_raw_mode(); enter_raw_mode(force_tty_flag);
if (compat20) { if (compat20) {
session_ident = ssh2_chan_id; session_ident = ssh2_chan_id;
@ -1441,12 +1442,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/* Buffer input from the connection. */ /* Buffer input from the connection. */
client_process_net_input(readset); client_process_net_input(readset);
/* Accept control connections. */
if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) {
if (muxserver_accept_control())
quit_pending = 1;
}
if (quit_pending) if (quit_pending)
break; break;
@ -1460,6 +1455,14 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
client_process_output(writeset); client_process_output(writeset);
} }
if (session_resumed) {
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
max_fd = MAX(max_fd, connection_out);
max_fd = MAX(max_fd, connection_in);
session_resumed = 0;
}
/* /*
* Send as much buffered packet data as possible to the * Send as much buffered packet data as possible to the
* sender. * sender.
@ -1488,7 +1491,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
channel_free_all(); channel_free_all();
if (have_pty) if (have_pty)
leave_raw_mode(); leave_raw_mode(force_tty_flag);
/* restore blocking io */ /* restore blocking io */
if (!isatty(fileno(stdin))) if (!isatty(fileno(stdin)))
@ -1846,15 +1849,17 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
chan_rcvd_eow(c); chan_rcvd_eow(c);
} else if (strcmp(rtype, "exit-status") == 0) { } else if (strcmp(rtype, "exit-status") == 0) {
exitval = packet_get_int(); exitval = packet_get_int();
if (id == session_ident) { if (c->ctl_chan != -1) {
mux_exit_message(c, exitval);
success = 1;
} else if (id == session_ident) {
/* Record exit value of local session */
success = 1; success = 1;
exit_status = exitval; exit_status = exitval;
} else if (c->ctl_fd == -1) {
error("client_input_channel_req: unexpected channel %d",
session_ident);
} else { } else {
atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval)); /* Probably for a mux channel that has already closed */
success = 1; debug("%s: no sink for exit-status on channel %d",
__func__, id);
} }
packet_check_eom(); packet_check_eom();
} }
@ -2050,7 +2055,7 @@ client_init_dispatch(void)
void void
cleanup_exit(int i) cleanup_exit(int i)
{ {
leave_raw_mode(); leave_raw_mode(force_tty_flag);
leave_non_blocking(); leave_non_blocking();
if (options.control_path != NULL && muxserver_sock != -1) if (options.control_path != NULL && muxserver_sock != -1)
unlink(options.control_path); unlink(options.control_path);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.h,v 1.22 2008/06/12 15:19:17 djm Exp $ */ /* $OpenBSD: clientloop.h,v 1.23 2010/01/26 01:28:35 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -56,18 +56,14 @@ typedef void global_confirm_cb(int, u_int32_t seq, void *);
void client_register_global_confirm(global_confirm_cb *, void *); void client_register_global_confirm(global_confirm_cb *, void *);
/* Multiplexing protocol version */ /* Multiplexing protocol version */
#define SSHMUX_VER 2 #define SSHMUX_VER 4
/* Multiplexing control protocol flags */ /* Multiplexing control protocol flags */
#define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ #define SSHMUX_COMMAND_OPEN 1 /* Open new connection */
#define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */ #define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */
#define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ #define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */
#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
#define SSHMUX_FLAG_TTY (1) /* Request tty on open */
#define SSHMUX_FLAG_SUBSYS (1<<1) /* Subsystem request on open */
#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */
#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */
void muxserver_listen(void); void muxserver_listen(void);
int muxserver_accept_control(void);
void muxclient(const char *); void muxclient(const char *);
void mux_exit_message(Channel *, int);

View File

@ -1,10 +1,10 @@
#! /bin/sh #! /bin/sh
# Attempt to guess a canonical system name. # Attempt to guess a canonical system name.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
# Free Software Foundation, Inc. # Free Software Foundation, Inc.
timestamp='2008-04-14' timestamp='2009-12-30'
# This file is free software; you can redistribute it and/or modify it # This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@ -27,16 +27,16 @@ timestamp='2008-04-14'
# the same distribution terms that you use for the rest of that program. # the same distribution terms that you use for the rest of that program.
# Originally written by Per Bothner <per@bothner.com>. # Originally written by Per Bothner. Please send patches (context
# Please send patches to <config-patches@gnu.org>. Submit a context # diff format) to <config-patches@gnu.org> and include a ChangeLog
# diff and a properly formatted ChangeLog entry. # entry.
# #
# This script attempts to guess a canonical system name similar to # This script attempts to guess a canonical system name similar to
# config.sub. If it succeeds, it prints the system name on stdout, and # config.sub. If it succeeds, it prints the system name on stdout, and
# exits with 0. Otherwise, it exits with 1. # exits with 0. Otherwise, it exits with 1.
# #
# The plan is that this can be called by configure scripts if you # You can get the latest version of this script from:
# don't specify an explicit build system type. # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
me=`echo "$0" | sed -e 's,.*/,,'` me=`echo "$0" | sed -e 's,.*/,,'`
@ -56,8 +56,9 @@ version="\
GNU config.guess ($timestamp) GNU config.guess ($timestamp)
Originally written by Per Bothner. Originally written by Per Bothner.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@ -170,7 +171,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax) arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep __ELF__ >/dev/null | grep -q __ELF__
then then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX? # Return netbsd for either. FIX?
@ -324,14 +325,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
case `/usr/bin/uname -p` in case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7; exit ;; sparc) echo sparc-icl-nx7; exit ;;
esac ;; esac ;;
s390x:SunOS:*:*)
echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4H:SunOS:5.*:*) sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;; exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;; exit ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
echo i386-pc-auroraux${UNAME_RELEASE}
exit ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` eval $set_cc_for_build
SUN_ARCH="i386"
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH="x86_64"
fi
fi
echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;; exit ;;
sun4*:SunOS:6*:*) sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize # According to config.sub, this is the proper way to canonicalize
@ -640,7 +660,7 @@ EOF
# => hppa64-hp-hpux11.23 # => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
grep __LP64__ >/dev/null grep -q __LP64__
then then
HP_ARCH="hppa2.0w" HP_ARCH="hppa2.0w"
else else
@ -791,12 +811,12 @@ EOF
i*:PW*:*) i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32 echo ${UNAME_MACHINE}-pc-pw32
exit ;; exit ;;
*:Interix*:[3456]*) *:Interix*:*)
case ${UNAME_MACHINE} in case ${UNAME_MACHINE} in
x86) x86)
echo i586-pc-interix${UNAME_RELEASE} echo i586-pc-interix${UNAME_RELEASE}
exit ;; exit ;;
EM64T | authenticamd) authenticamd | genuineintel | EM64T)
echo x86_64-unknown-interix${UNAME_RELEASE} echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;; exit ;;
IA64) IA64)
@ -806,6 +826,9 @@ EOF
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks echo i${UNAME_MACHINE}-pc-mks
exit ;; exit ;;
8664:Windows_NT:*)
echo x86_64-pc-mks
exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*) i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem? # How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@ -835,6 +858,20 @@ EOF
i*86:Minix:*:*) i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix echo ${UNAME_MACHINE}-pc-minix
exit ;; exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
PCA57) UNAME_MACHINE=alphapca56 ;;
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;;
arm*:Linux:*:*) arm*:Linux:*:*)
eval $set_cc_for_build eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
@ -857,6 +894,17 @@ EOF
frv:Linux:*:*) frv:Linux:*:*)
echo frv-unknown-linux-gnu echo frv-unknown-linux-gnu
exit ;; exit ;;
i*86:Linux:*:*)
LIBC=gnu
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#ifdef __dietlibc__
LIBC=dietlibc
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit ;;
ia64:Linux:*:*) ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;; exit ;;
@ -866,74 +914,33 @@ EOF
m68*:Linux:*:*) m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;; exit ;;
mips:Linux:*:*) mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c sed 's/^ //' << EOF >$dummy.c
#undef CPU #undef CPU
#undef mips #undef ${UNAME_MACHINE}
#undef mipsel #undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mipsel CPU=${UNAME_MACHINE}el
#else #else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips CPU=${UNAME_MACHINE}
#else #else
CPU= CPU=
#endif #endif
#endif #endif
EOF EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
/^CPU/{
s: ::g
p
}'`"
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
#undef mips64
#undef mips64el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
CPU=mips64el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
CPU=mips64
#else
CPU=
#endif
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^CPU/{
s: ::g
p
}'`"
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;; ;;
or32:Linux:*:*) or32:Linux:*:*)
echo or32-unknown-linux-gnu echo or32-unknown-linux-gnu
exit ;; exit ;;
ppc:Linux:*:*) padre:Linux:*:*)
echo powerpc-unknown-linux-gnu echo sparc-unknown-linux-gnu
exit ;; exit ;;
ppc64:Linux:*:*) parisc64:Linux:*:* | hppa64:Linux:*:*)
echo powerpc64-unknown-linux-gnu echo hppa64-unknown-linux-gnu
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
PCA57) UNAME_MACHINE=alphapca56 ;;
EV6) UNAME_MACHINE=alphaev6 ;;
EV67) UNAME_MACHINE=alphaev67 ;;
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;; exit ;;
parisc:Linux:*:* | hppa:Linux:*:*) parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level # Look for CPU level
@ -943,8 +950,11 @@ EOF
*) echo hppa-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;;
esac esac
exit ;; exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*) ppc64:Linux:*:*)
echo hppa64-unknown-linux-gnu echo powerpc64-unknown-linux-gnu
exit ;;
ppc:Linux:*:*)
echo powerpc-unknown-linux-gnu
exit ;; exit ;;
s390:Linux:*:* | s390x:Linux:*:*) s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux echo ${UNAME_MACHINE}-ibm-linux
@ -967,66 +977,6 @@ EOF
xtensa*:Linux:*:*) xtensa*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;; exit ;;
i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
# first see if it will tell us. cd to the root directory to prevent
# problems with other programs or directories called `ld' in the path.
# Set LC_ALL=C to ensure ld outputs messages in English.
ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
| sed -ne '/supported targets:/!d
s/[ ][ ]*/ /g
s/.*supported targets: *//
s/ .*//
p'`
case "$ld_supported_targets" in
elf32-i386)
TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
;;
a.out-i386-linux)
echo "${UNAME_MACHINE}-pc-linux-gnuaout"
exit ;;
"")
# Either a pre-BFD a.out linker (linux-gnuoldld) or
# one that does not give us useful --help.
echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
exit ;;
esac
# Determine whether the default compiler is a.out or elf
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#include <features.h>
#ifdef __ELF__
# ifdef __GLIBC__
# if __GLIBC__ >= 2
LIBC=gnu
# else
LIBC=gnulibc1
# endif
# else
LIBC=gnulibc1
# endif
#else
#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
LIBC=gnu
#else
LIBC=gnuaout
#endif
#endif
#ifdef __dietlibc__
LIBC=dietlibc
#endif
EOF
eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
/^LIBC/{
s: ::g
p
}'`"
test x"${LIBC}" != x && {
echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit
}
test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
;;
i*86:DYNIX/ptx:4*:*) i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both # earlier versions are messed up and put the nodename in both
@ -1055,7 +1005,7 @@ EOF
i*86:syllable:*:*) i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable echo ${UNAME_MACHINE}-pc-syllable
exit ;; exit ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE} echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
i*86:*DOS:*:*) i*86:*DOS:*:*)
@ -1099,8 +1049,11 @@ EOF
pc:*:*:*) pc:*:*:*)
# Left here for compatibility: # Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about # uname -m prints for DJGPP always 'pc', but it prints nothing about
# the processor, so we play safe by assuming i386. # the processor, so we play safe by assuming i586.
echo i386-pc-msdosdjgpp # Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configury will decide that
# this is a cross-build.
echo i586-pc-msdosdjgpp
exit ;; exit ;;
Intel:Mach:3*:*) Intel:Mach:3*:*)
echo i386-pc-mach3 echo i386-pc-mach3
@ -1138,6 +1091,16 @@ EOF
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4; exit; } ;; && { echo i486-ncr-sysv4; exit; } ;;
NCR*:*:4.2:* | MPRAS*:*:4.2:*)
OS_REL='.3'
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
&& { echo i486-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; }
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE} echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
@ -1150,7 +1113,7 @@ EOF
rs6000:LynxOS:2.*:*) rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE} echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE} echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;; exit ;;
SM[BE]S:UNIX_SV:*:*) SM[BE]S:UNIX_SV:*:*)
@ -1243,6 +1206,16 @@ EOF
*:Darwin:*:*) *:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
case $UNAME_PROCESSOR in case $UNAME_PROCESSOR in
i386)
eval $set_cc_for_build
if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
UNAME_PROCESSOR="x86_64"
fi
fi ;;
unknown) UNAME_PROCESSOR=powerpc ;; unknown) UNAME_PROCESSOR=powerpc ;;
esac esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@ -1324,6 +1297,9 @@ EOF
i*86:rdos:*:*) i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos echo ${UNAME_MACHINE}-pc-rdos
exit ;; exit ;;
i*86:AROS:*:*)
echo ${UNAME_MACHINE}-pc-aros
exit ;;
esac esac
#echo '(No uname command or uname output not recognized.)' 1>&2 #echo '(No uname command or uname output not recognized.)' 1>&2

View File

@ -123,6 +123,9 @@
/* Define if you don't want to use wtmpx */ /* Define if you don't want to use wtmpx */
#define DISABLE_WTMPX 1 #define DISABLE_WTMPX 1
/* Enable for PKCS#11 support */
#define ENABLE_PKCS11
/* Builtin PRNG command timeout */ /* Builtin PRNG command timeout */
#define ENTROPY_TIMEOUT_MSEC 200 #define ENTROPY_TIMEOUT_MSEC 200
@ -462,6 +465,9 @@
/* Define to 1 if you have the <glob.h> header file. */ /* Define to 1 if you have the <glob.h> header file. */
#define HAVE_GLOB_H 1 #define HAVE_GLOB_H 1
/* Define to 1 if you have the `group_from_gid' function. */
#define HAVE_GROUP_FROM_GID 1
/* Define to 1 if you have the <gssapi_generic.h> header file. */ /* Define to 1 if you have the <gssapi_generic.h> header file. */
/* #undef HAVE_GSSAPI_GENERIC_H */ /* #undef HAVE_GSSAPI_GENERIC_H */
@ -552,9 +558,6 @@
/* Define to 1 if you have the `pam' library (-lpam). */ /* Define to 1 if you have the `pam' library (-lpam). */
#define HAVE_LIBPAM 1 #define HAVE_LIBPAM 1
/* Define to 1 if you have the `sectok' library (-lsectok). */
/* #undef HAVE_LIBSECTOK */
/* Define to 1 if you have the `socket' library (-lsocket). */ /* Define to 1 if you have the `socket' library (-lsocket). */
/* #undef HAVE_LIBSOCKET */ /* #undef HAVE_LIBSOCKET */
@ -736,9 +739,6 @@
/* define if you have sa_family_t data type */ /* define if you have sa_family_t data type */
#define HAVE_SA_FAMILY_T 1 #define HAVE_SA_FAMILY_T 1
/* Define to 1 if you have the <sectok.h> header file. */
/* #undef HAVE_SECTOK_H */
/* Define if you have SecureWare-based protected password database */ /* Define if you have SecureWare-based protected password database */
/* #undef HAVE_SECUREWARE */ /* #undef HAVE_SECUREWARE */
@ -763,6 +763,9 @@
/* Define to 1 if you have the `seteuid' function. */ /* Define to 1 if you have the `seteuid' function. */
#define HAVE_SETEUID 1 #define HAVE_SETEUID 1
/* Define to 1 if you have the `setgroupent' function. */
#define HAVE_SETGROUPENT 1
/* Define to 1 if you have the `setgroups' function. */ /* Define to 1 if you have the `setgroups' function. */
#define HAVE_SETGROUPS 1 #define HAVE_SETGROUPS 1
@ -772,6 +775,9 @@
/* Define to 1 if you have the `setluid' function. */ /* Define to 1 if you have the `setluid' function. */
/* #undef HAVE_SETLUID */ /* #undef HAVE_SETLUID */
/* Define to 1 if you have the `setpassent' function. */
#define HAVE_SETPASSENT 1
/* Define to 1 if you have the `setpcred' function. */ /* Define to 1 if you have the `setpcred' function. */
/* #undef HAVE_SETPCRED */ /* #undef HAVE_SETPCRED */
@ -1075,6 +1081,9 @@
/* Define to 1 if you have the <usersec.h> header file. */ /* Define to 1 if you have the <usersec.h> header file. */
/* #undef HAVE_USERSEC_H */ /* #undef HAVE_USERSEC_H */
/* Define to 1 if you have the `user_from_uid' function. */
#define HAVE_USER_FROM_UID 1
/* Define to 1 if you have the <util.h> header file. */ /* Define to 1 if you have the <util.h> header file. */
/* #undef HAVE_UTIL_H */ /* #undef HAVE_UTIL_H */
@ -1184,6 +1193,9 @@
EOPNOTSUPP. */ EOPNOTSUPP. */
/* #undef LINK_OPNOTSUPP_ERRNO */ /* #undef LINK_OPNOTSUPP_ERRNO */
/* Adjust Linux out-of-memory killer */
/* #undef LINUX_OOM_ADJUST */
/* max value of long long calculated by configure */ /* max value of long long calculated by configure */
/* #undef LLONG_MAX */ /* #undef LLONG_MAX */
@ -1303,9 +1315,6 @@
/* Define if your skeychallenge() function takes 4 arguments (NetBSD) */ /* Define if your skeychallenge() function takes 4 arguments (NetBSD) */
/* #undef SKEYCHALLENGE_4ARG */ /* #undef SKEYCHALLENGE_4ARG */
/* Define if you want smartcard support */
/* #undef SMARTCARD */
/* Define as const if snprintf() can declare const char *fmt */ /* Define as const if snprintf() can declare const char *fmt */
#define SNPRINTF_CONST const #define SNPRINTF_CONST const
@ -1373,9 +1382,6 @@
/* Use libedit for sftp */ /* Use libedit for sftp */
#define USE_LIBEDIT 1 #define USE_LIBEDIT 1
/* Define if you want smartcard support using OpenSC */
/* #undef USE_OPENSC */
/* Enable OpenSSL engine support */ /* Enable OpenSSL engine support */
#define USE_OPENSSL_ENGINE 1 #define USE_OPENSSL_ENGINE 1
@ -1385,9 +1391,6 @@
/* Use PIPES instead of a socketpair() */ /* Use PIPES instead of a socketpair() */
/* #undef USE_PIPES */ /* #undef USE_PIPES */
/* Define if you want smartcard support using sectok */
/* #undef USE_SECTOK */
/* Define if you have Solaris process contracts */ /* Define if you have Solaris process contracts */
/* #undef USE_SOLARIS_PROCESS_CONTRACTS */ /* #undef USE_SOLARIS_PROCESS_CONTRACTS */
@ -1413,8 +1416,8 @@
/* Define if you want SELinux support. */ /* Define if you want SELinux support. */
/* #undef WITH_SELINUX */ /* #undef WITH_SELINUX */
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most /* Define to 1 if your processor stores words with the most significant byte
significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ first (like Motorola and SPARC, unlike Intel and VAX). */
#if defined __BIG_ENDIAN__ #if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1 # define WORDS_BIGENDIAN 1
#elif ! defined __LITTLE_ENDIAN__ #elif ! defined __LITTLE_ENDIAN__

View File

@ -1,8 +1,5 @@
/* config.h.in. Generated from configure.ac by autoheader. */ /* config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address /* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address
*/ */
#undef AIX_GETNAMEINFO_HACK #undef AIX_GETNAMEINFO_HACK
@ -125,6 +122,9 @@
/* Define if you don't want to use wtmpx */ /* Define if you don't want to use wtmpx */
#undef DISABLE_WTMPX #undef DISABLE_WTMPX
/* Enable for PKCS#11 support */
#undef ENABLE_PKCS11
/* Builtin PRNG command timeout */ /* Builtin PRNG command timeout */
#undef ENTROPY_TIMEOUT_MSEC #undef ENTROPY_TIMEOUT_MSEC
@ -464,6 +464,9 @@
/* Define to 1 if you have the <glob.h> header file. */ /* Define to 1 if you have the <glob.h> header file. */
#undef HAVE_GLOB_H #undef HAVE_GLOB_H
/* Define to 1 if you have the `group_from_gid' function. */
#undef HAVE_GROUP_FROM_GID
/* Define to 1 if you have the <gssapi_generic.h> header file. */ /* Define to 1 if you have the <gssapi_generic.h> header file. */
#undef HAVE_GSSAPI_GENERIC_H #undef HAVE_GSSAPI_GENERIC_H
@ -554,9 +557,6 @@
/* Define to 1 if you have the `pam' library (-lpam). */ /* Define to 1 if you have the `pam' library (-lpam). */
#undef HAVE_LIBPAM #undef HAVE_LIBPAM
/* Define to 1 if you have the `sectok' library (-lsectok). */
#undef HAVE_LIBSECTOK
/* Define to 1 if you have the `socket' library (-lsocket). */ /* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET #undef HAVE_LIBSOCKET
@ -738,9 +738,6 @@
/* define if you have sa_family_t data type */ /* define if you have sa_family_t data type */
#undef HAVE_SA_FAMILY_T #undef HAVE_SA_FAMILY_T
/* Define to 1 if you have the <sectok.h> header file. */
#undef HAVE_SECTOK_H
/* Define if you have SecureWare-based protected password database */ /* Define if you have SecureWare-based protected password database */
#undef HAVE_SECUREWARE #undef HAVE_SECUREWARE
@ -765,6 +762,9 @@
/* Define to 1 if you have the `seteuid' function. */ /* Define to 1 if you have the `seteuid' function. */
#undef HAVE_SETEUID #undef HAVE_SETEUID
/* Define to 1 if you have the `setgroupent' function. */
#undef HAVE_SETGROUPENT
/* Define to 1 if you have the `setgroups' function. */ /* Define to 1 if you have the `setgroups' function. */
#undef HAVE_SETGROUPS #undef HAVE_SETGROUPS
@ -774,6 +774,9 @@
/* Define to 1 if you have the `setluid' function. */ /* Define to 1 if you have the `setluid' function. */
#undef HAVE_SETLUID #undef HAVE_SETLUID
/* Define to 1 if you have the `setpassent' function. */
#undef HAVE_SETPASSENT
/* Define to 1 if you have the `setpcred' function. */ /* Define to 1 if you have the `setpcred' function. */
#undef HAVE_SETPCRED #undef HAVE_SETPCRED
@ -1077,6 +1080,9 @@
/* Define to 1 if you have the <usersec.h> header file. */ /* Define to 1 if you have the <usersec.h> header file. */
#undef HAVE_USERSEC_H #undef HAVE_USERSEC_H
/* Define to 1 if you have the `user_from_uid' function. */
#undef HAVE_USER_FROM_UID
/* Define to 1 if you have the <util.h> header file. */ /* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H #undef HAVE_UTIL_H
@ -1186,6 +1192,9 @@
EOPNOTSUPP. */ EOPNOTSUPP. */
#undef LINK_OPNOTSUPP_ERRNO #undef LINK_OPNOTSUPP_ERRNO
/* Adjust Linux out-of-memory killer */
#undef LINUX_OOM_ADJUST
/* max value of long long calculated by configure */ /* max value of long long calculated by configure */
#undef LLONG_MAX #undef LLONG_MAX
@ -1305,9 +1314,6 @@
/* Define if your skeychallenge() function takes 4 arguments (NetBSD) */ /* Define if your skeychallenge() function takes 4 arguments (NetBSD) */
#undef SKEYCHALLENGE_4ARG #undef SKEYCHALLENGE_4ARG
/* Define if you want smartcard support */
#undef SMARTCARD
/* Define as const if snprintf() can declare const char *fmt */ /* Define as const if snprintf() can declare const char *fmt */
#undef SNPRINTF_CONST #undef SNPRINTF_CONST
@ -1375,9 +1381,6 @@
/* Use libedit for sftp */ /* Use libedit for sftp */
#undef USE_LIBEDIT #undef USE_LIBEDIT
/* Define if you want smartcard support using OpenSC */
#undef USE_OPENSC
/* Enable OpenSSL engine support */ /* Enable OpenSSL engine support */
#undef USE_OPENSSL_ENGINE #undef USE_OPENSSL_ENGINE
@ -1387,9 +1390,6 @@
/* Use PIPES instead of a socketpair() */ /* Use PIPES instead of a socketpair() */
#undef USE_PIPES #undef USE_PIPES
/* Define if you want smartcard support using sectok */
#undef USE_SECTOK
/* Define if you have Solaris process contracts */ /* Define if you have Solaris process contracts */
#undef USE_SOLARIS_PROCESS_CONTRACTS #undef USE_SOLARIS_PROCESS_CONTRACTS
@ -1415,17 +1415,9 @@
/* Define if you want SELinux support. */ /* Define if you want SELinux support. */
#undef WITH_SELINUX #undef WITH_SELINUX
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most /* Define to 1 if your processor stores words with the most significant byte
significant byte first (like Motorola and SPARC, unlike Intel). */ first (like Motorola and SPARC, unlike Intel and VAX). */
#if defined AC_APPLE_UNIVERSAL_BUILD #undef WORDS_BIGENDIAN
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
/* Define if xauth is found in your path */ /* Define if xauth is found in your path */
#undef XAUTH_PATH #undef XAUTH_PATH

View File

@ -25,7 +25,7 @@
#ifndef _DEFINES_H #ifndef _DEFINES_H
#define _DEFINES_H #define _DEFINES_H
/* $Id: defines.h,v 1.156 2009/08/28 01:21:07 dtucker Exp $ */ /* $Id: defines.h,v 1.159 2010/01/13 23:44:34 tim Exp $ */
/* Constants */ /* Constants */
@ -753,4 +753,12 @@ struct winsize {
# define SSH_IOBUFSZ 8192 # define SSH_IOBUFSZ 8192
#endif #endif
#ifndef _NSIG
# ifdef NSIG
# define _NSIG NSIG
# else
# define _NSIG 128
# endif
#endif
#endif /* _DEFINES_H */ #endif /* _DEFINES_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dh.c,v 1.47 2008/06/26 09:19:39 djm Exp $ */ /* $OpenBSD: dh.c,v 1.48 2009/10/01 11:37:33 grunk Exp $ */
/* /*
* Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2000 Niels Provos. All rights reserved.
* *
@ -83,7 +83,7 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
goto fail; goto fail;
strsize = strsep(&cp, " "); /* size */ strsize = strsep(&cp, " "); /* size */
if (cp == NULL || *strsize == '\0' || if (cp == NULL || *strsize == '\0' ||
(dhg->size = (u_int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 || (dhg->size = (int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
errstr) errstr)
goto fail; goto fail;
/* The whole group is one bit larger */ /* The whole group is one bit larger */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dns.c,v 1.25 2008/06/12 00:03:49 dtucker Exp $ */ /* $OpenBSD: dns.c,v 1.26 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2003 Wesley Griffin. All rights reserved. * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@ -75,7 +75,7 @@ dns_result_totext(unsigned int res)
*/ */
static int static int
dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
u_char **digest, u_int *digest_len, const Key *key) u_char **digest, u_int *digest_len, Key *key)
{ {
int success = 0; int success = 0;
@ -172,7 +172,7 @@ is_numeric_hostname(const char *hostname)
*/ */
int int
verify_host_key_dns(const char *hostname, struct sockaddr *address, verify_host_key_dns(const char *hostname, struct sockaddr *address,
const Key *hostkey, int *flags) Key *hostkey, int *flags)
{ {
u_int counter; u_int counter;
int result; int result;
@ -271,7 +271,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
* Export the fingerprint of a key as a DNS resource record * Export the fingerprint of a key as a DNS resource record
*/ */
int int
export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic) export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
{ {
u_int8_t rdata_pubkey_algorithm = 0; u_int8_t rdata_pubkey_algorithm = 0;
u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dns.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */ /* $OpenBSD: dns.h,v 1.11 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2003 Wesley Griffin. All rights reserved. * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@ -46,7 +46,7 @@ enum sshfp_hashes {
#define DNS_VERIFY_MATCH 0x00000002 #define DNS_VERIFY_MATCH 0x00000002
#define DNS_VERIFY_SECURE 0x00000004 #define DNS_VERIFY_SECURE 0x00000004
int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *); int verify_host_key_dns(const char *, struct sockaddr *, Key *, int *);
int export_dns_rr(const char *, const Key *, FILE *, int); int export_dns_rr(const char *, Key *, FILE *, int);
#endif /* DNS_H */ #endif /* DNS_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: hostfile.c,v 1.45 2006/08/03 03:34:42 deraadt Exp $ */ /* $OpenBSD: hostfile.c,v 1.48 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -183,6 +183,41 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen
return 1; return 1;
} }
static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA }
check_markers(char **cpp)
{
char marker[32], *sp, *cp = *cpp;
int ret = MRK_NONE;
while (*cp == '@') {
/* Only one marker is allowed */
if (ret != MRK_NONE)
return MRK_ERROR;
/* Markers are terminated by whitespace */
if ((sp = strchr(cp, ' ')) == NULL &&
(sp = strchr(cp, '\t')) == NULL)
return MRK_ERROR;
/* Extract marker for comparison */
if (sp <= cp + 1 || sp >= cp + sizeof(marker))
return MRK_ERROR;
memcpy(marker, cp, sp - cp);
marker[sp - cp] = '\0';
if (strcmp(marker, CA_MARKER) == 0)
ret = MRK_CA;
else if (strcmp(marker, REVOKE_MARKER) == 0)
ret = MRK_REVOKE;
else
return MRK_ERROR;
/* Skip past marker and any whitespace that follows it */
cp = sp;
for (; *cp == ' ' || *cp == '\t'; cp++)
;
}
*cpp = cp;
return ret;
}
/* /*
* Checks whether the given host (which must be in all lowercase) is already * Checks whether the given host (which must be in all lowercase) is already
* in the list of our known hosts. Returns HOST_OK if the host is known and * in the list of our known hosts. Returns HOST_OK if the host is known and
@ -195,16 +230,20 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen
static HostStatus static HostStatus
check_host_in_hostfile_by_key_or_type(const char *filename, check_host_in_hostfile_by_key_or_type(const char *filename,
const char *host, const Key *key, int keytype, Key *found, int *numret) const char *host, const Key *key, int keytype, Key *found,
int want_revocation, int *numret)
{ {
FILE *f; FILE *f;
char line[8192]; char line[8192];
int linenum = 0; int want, have, linenum = 0, want_cert = key_is_cert(key);
u_int kbits; u_int kbits;
char *cp, *cp2, *hashed_host; char *cp, *cp2, *hashed_host;
HostStatus end_return; HostStatus end_return;
debug3("check_host_in_hostfile: filename %s", filename); debug3("check_host_in_hostfile: host %s filename %s", host, filename);
if (want_revocation && (key == NULL || keytype != 0 || found != NULL))
fatal("%s: invalid arguments", __func__);
/* Open the file containing the list of known hosts. */ /* Open the file containing the list of known hosts. */
f = fopen(filename, "r"); f = fopen(filename, "r");
@ -229,6 +268,20 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
if (!*cp || *cp == '#' || *cp == '\n') if (!*cp || *cp == '#' || *cp == '\n')
continue; continue;
if (want_revocation)
want = MRK_REVOKE;
else if (want_cert)
want = MRK_CA;
else
want = MRK_NONE;
if ((have = check_markers(&cp)) == MRK_ERROR) {
verbose("%s: invalid marker at %s:%d",
__func__, filename, linenum);
continue;
} else if (want != have)
continue;
/* Find the end of the host name portion. */ /* Find the end of the host name portion. */
for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
; ;
@ -250,6 +303,9 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
/* Got a match. Skip host name. */ /* Got a match. Skip host name. */
cp = cp2; cp = cp2;
if (want_revocation)
found = key_new(KEY_UNSPEC);
/* /*
* Extract the key from the line. This will skip any leading * Extract the key from the line. This will skip any leading
* whitespace. Ignore badly formatted lines. * whitespace. Ignore badly formatted lines.
@ -272,9 +328,33 @@ check_host_in_hostfile_by_key_or_type(const char *filename,
if (!hostfile_check_key(kbits, found, host, filename, linenum)) if (!hostfile_check_key(kbits, found, host, filename, linenum))
continue; continue;
if (want_revocation) {
if (key_is_cert(key) &&
key_equal_public(key->cert->signature_key, found)) {
verbose("check_host_in_hostfile: revoked CA "
"line %d", linenum);
key_free(found);
return HOST_REVOKED;
}
if (key_equal_public(key, found)) {
verbose("check_host_in_hostfile: revoked key "
"line %d", linenum);
key_free(found);
return HOST_REVOKED;
}
key_free(found);
continue;
}
/* Check if the current key is the same as the given key. */ /* Check if the current key is the same as the given key. */
if (key_equal(key, found)) { if (want_cert && key_equal(key->cert->signature_key, found)) {
/* Ok, they match. */ /* Found CA cert for key */
debug3("check_host_in_hostfile: CA match line %d",
linenum);
fclose(f);
return HOST_OK;
} else if (!want_cert && key_equal(key, found)) {
/* Found identical key */
debug3("check_host_in_hostfile: match line %d", linenum); debug3("check_host_in_hostfile: match line %d", linenum);
fclose(f); fclose(f);
return HOST_OK; return HOST_OK;
@ -302,8 +382,11 @@ check_host_in_hostfile(const char *filename, const char *host, const Key *key,
{ {
if (key == NULL) if (key == NULL)
fatal("no key to look up"); fatal("no key to look up");
return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, if (check_host_in_hostfile_by_key_or_type(filename, host,
found, numret)); key, 0, NULL, 1, NULL) == HOST_REVOKED)
return HOST_REVOKED;
return check_host_in_hostfile_by_key_or_type(filename, host, key, 0,
found, 0, numret);
} }
int int
@ -311,7 +394,7 @@ lookup_key_in_hostfile_by_type(const char *filename, const char *host,
int keytype, Key *found, int *numret) int keytype, Key *found, int *numret)
{ {
return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, return (check_host_in_hostfile_by_key_or_type(filename, host, NULL,
keytype, found, numret) == HOST_FOUND); keytype, found, 0, numret) == HOST_FOUND);
} }
/* /*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: hostfile.h,v 1.16 2006/03/25 22:22:43 djm Exp $ */ /* $OpenBSD: hostfile.h,v 1.18 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -15,7 +15,7 @@
#define HOSTFILE_H #define HOSTFILE_H
typedef enum { typedef enum {
HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND HOST_OK, HOST_NEW, HOST_CHANGED, HOST_REVOKED, HOST_FOUND
} HostStatus; } HostStatus;
int hostfile_read_key(char **, u_int *, Key *); int hostfile_read_key(char **, u_int *, Key *);
@ -28,6 +28,9 @@ int lookup_key_in_hostfile_by_type(const char *, const char *,
#define HASH_MAGIC "|1|" #define HASH_MAGIC "|1|"
#define HASH_DELIM '|' #define HASH_DELIM '|'
#define CA_MARKER "@cert-authority"
#define REVOKE_MARKER "@revoked"
char *host_hash(const char *, const char *, u_int); char *host_hash(const char *, const char *, u_int);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.81 2009/05/27 06:34:36 andreas Exp $ */ /* $OpenBSD: kex.c,v 1.82 2009/10/24 11:13:54 andreas Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* *
@ -48,6 +48,7 @@
#include "match.h" #include "match.h"
#include "dispatch.h" #include "dispatch.h"
#include "monitor.h" #include "monitor.h"
#include "roaming.h"
#if OPENSSL_VERSION_NUMBER >= 0x00907000L #if OPENSSL_VERSION_NUMBER >= 0x00907000L
# if defined(HAVE_EVP_SHA256) # if defined(HAVE_EVP_SHA256)
@ -386,6 +387,16 @@ kex_choose_conf(Kex *kex)
sprop=peer; sprop=peer;
} }
/* Check whether server offers roaming */
if (!kex->server) {
char *roaming;
roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL);
if (roaming) {
kex->roaming = 1;
xfree(roaming);
}
}
/* Algorithm Negotiation */ /* Algorithm Negotiation */
for (mode = 0; mode < MODE_MAX; mode++) { for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = xcalloc(1, sizeof(*newkeys)); newkeys = xcalloc(1, sizeof(*newkeys));

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.47 2009/05/27 06:34:36 andreas Exp $ */ /* $OpenBSD: kex.h,v 1.49 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -36,6 +36,7 @@
#define KEX_DH14 "diffie-hellman-group14-sha1" #define KEX_DH14 "diffie-hellman-group14-sha1"
#define KEX_DHGEX_SHA1 "diffie-hellman-group-exchange-sha1" #define KEX_DHGEX_SHA1 "diffie-hellman-group-exchange-sha1"
#define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256" #define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256"
#define KEX_RESUME "resume@appgate.com"
#define COMP_NONE 0 #define COMP_NONE 0
#define COMP_ZLIB 1 #define COMP_ZLIB 1
@ -116,6 +117,7 @@ struct Kex {
char *name; char *name;
int hostkey_type; int hostkey_type;
int kex_type; int kex_type;
int roaming;
Buffer my; Buffer my;
Buffer peer; Buffer peer;
sig_atomic_t done; sig_atomic_t done;
@ -124,7 +126,8 @@ struct Kex {
char *client_version_string; char *client_version_string;
char *server_version_string; char *server_version_string;
int (*verify_host_key)(Key *); int (*verify_host_key)(Key *);
Key *(*load_host_key)(int); Key *(*load_host_public_key)(int);
Key *(*load_host_private_key)(int);
int (*host_key_index)(Key *); int (*host_key_index)(Key *);
void (*kex[KEX_MAX])(Kex *); void (*kex[KEX_MAX])(Kex *);
}; };

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexdhs.c,v 1.10 2009/06/21 07:37:15 dtucker Exp $ */ /* $OpenBSD: kexdhs.c,v 1.11 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
* *
@ -50,7 +50,7 @@ kexdh_server(Kex *kex)
{ {
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
DH *dh; DH *dh;
Key *server_host_key; Key *server_host_public, *server_host_private;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, hashlen, slen; u_int sbloblen, klen, hashlen, slen;
int kout; int kout;
@ -71,11 +71,16 @@ kexdh_server(Kex *kex)
debug("expecting SSH2_MSG_KEXDH_INIT"); debug("expecting SSH2_MSG_KEXDH_INIT");
packet_read_expect(SSH2_MSG_KEXDH_INIT); packet_read_expect(SSH2_MSG_KEXDH_INIT);
if (kex->load_host_key == NULL) if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL)
fatal("Cannot load hostkey"); fatal("Cannot load hostkey");
server_host_key = kex->load_host_key(kex->hostkey_type); server_host_public = kex->load_host_public_key(kex->hostkey_type);
if (server_host_key == NULL) if (server_host_public == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type); fatal("Unsupported hostkey type %d", kex->hostkey_type);
server_host_private = kex->load_host_private_key(kex->hostkey_type);
if (server_host_private == NULL)
fatal("Missing private key for hostkey type %d",
kex->hostkey_type);
/* key, cert */ /* key, cert */
if ((dh_client_pub = BN_new()) == NULL) if ((dh_client_pub = BN_new()) == NULL)
@ -113,7 +118,7 @@ kexdh_server(Kex *kex)
memset(kbuf, 0, klen); memset(kbuf, 0, klen);
xfree(kbuf); xfree(kbuf);
key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
/* calc H */ /* calc H */
kex_dh_hash( kex_dh_hash(
@ -137,7 +142,7 @@ kexdh_server(Kex *kex)
} }
/* sign H */ /* sign H */
if (PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash,
hashlen)) < 0) hashlen)) < 0)
fatal("kexdh_server: key_sign failed"); fatal("kexdh_server: key_sign failed");

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexs.c,v 1.12 2009/06/21 07:37:15 dtucker Exp $ */ /* $OpenBSD: kexgexs.c,v 1.13 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -52,18 +52,24 @@ void
kexgex_server(Kex *kex) kexgex_server(Kex *kex)
{ {
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
Key *server_host_key; Key *server_host_public, *server_host_private;
DH *dh; DH *dh;
u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
u_int sbloblen, klen, slen, hashlen; u_int sbloblen, klen, slen, hashlen;
int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1;
int type, kout; int type, kout;
if (kex->load_host_key == NULL) if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL)
fatal("Cannot load hostkey"); fatal("Cannot load hostkey");
server_host_key = kex->load_host_key(kex->hostkey_type); server_host_public = kex->load_host_public_key(kex->hostkey_type);
if (server_host_key == NULL) if (server_host_public == NULL)
fatal("Unsupported hostkey type %d", kex->hostkey_type); fatal("Unsupported hostkey type %d", kex->hostkey_type);
server_host_private = kex->load_host_private_key(kex->hostkey_type);
if (server_host_private == NULL)
fatal("Missing private key for hostkey type %d",
kex->hostkey_type);
type = packet_read(); type = packet_read();
switch (type) { switch (type) {
@ -149,7 +155,7 @@ kexgex_server(Kex *kex)
memset(kbuf, 0, klen); memset(kbuf, 0, klen);
xfree(kbuf); xfree(kbuf);
key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
omin = min = omax = max = -1; omin = min = omax = max = -1;
@ -179,7 +185,7 @@ kexgex_server(Kex *kex)
} }
/* sign H */ /* sign H */
if (PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash,
hashlen)) < 0) hashlen)) < 0)
fatal("kexgex_server: key_sign failed"); fatal("kexgex_server: key_sign failed");

View File

@ -1,4 +1,4 @@
/* $OpenBSD: key.c,v 1.80 2008/10/10 05:00:12 stevesk Exp $ */ /* $OpenBSD: key.c,v 1.85 2010/03/04 01:44:57 djm Exp $ */
/* /*
* read_bignum(): * read_bignum():
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -52,6 +52,21 @@
#include "uuencode.h" #include "uuencode.h"
#include "buffer.h" #include "buffer.h"
#include "log.h" #include "log.h"
#include "ssh2.h"
static struct KeyCert *
cert_new(void)
{
struct KeyCert *cert;
cert = xcalloc(1, sizeof(*cert));
buffer_init(&cert->certblob);
buffer_init(&cert->constraints);
cert->key_id = NULL;
cert->principals = NULL;
cert->signature_key = NULL;
return cert;
}
Key * Key *
key_new(int type) key_new(int type)
@ -63,9 +78,11 @@ key_new(int type)
k->type = type; k->type = type;
k->dsa = NULL; k->dsa = NULL;
k->rsa = NULL; k->rsa = NULL;
k->cert = NULL;
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
if ((rsa = RSA_new()) == NULL) if ((rsa = RSA_new()) == NULL)
fatal("key_new: RSA_new failed"); fatal("key_new: RSA_new failed");
if ((rsa->n = BN_new()) == NULL) if ((rsa->n = BN_new()) == NULL)
@ -75,6 +92,7 @@ key_new(int type)
k->rsa = rsa; k->rsa = rsa;
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
if ((dsa = DSA_new()) == NULL) if ((dsa = DSA_new()) == NULL)
fatal("key_new: DSA_new failed"); fatal("key_new: DSA_new failed");
if ((dsa->p = BN_new()) == NULL) if ((dsa->p = BN_new()) == NULL)
@ -93,16 +111,20 @@ key_new(int type)
fatal("key_new: bad key type %d", k->type); fatal("key_new: bad key type %d", k->type);
break; break;
} }
if (key_is_cert(k))
k->cert = cert_new();
return k; return k;
} }
Key * void
key_new_private(int type) key_add_private(Key *k)
{ {
Key *k = key_new(type);
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
if ((k->rsa->d = BN_new()) == NULL) if ((k->rsa->d = BN_new()) == NULL)
fatal("key_new_private: BN_new failed"); fatal("key_new_private: BN_new failed");
if ((k->rsa->iqmp = BN_new()) == NULL) if ((k->rsa->iqmp = BN_new()) == NULL)
@ -117,6 +139,7 @@ key_new_private(int type)
fatal("key_new_private: BN_new failed"); fatal("key_new_private: BN_new failed");
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
if ((k->dsa->priv_key = BN_new()) == NULL) if ((k->dsa->priv_key = BN_new()) == NULL)
fatal("key_new_private: BN_new failed"); fatal("key_new_private: BN_new failed");
break; break;
@ -125,9 +148,34 @@ key_new_private(int type)
default: default:
break; break;
} }
}
Key *
key_new_private(int type)
{
Key *k = key_new(type);
key_add_private(k);
return k; return k;
} }
static void
cert_free(struct KeyCert *cert)
{
u_int i;
buffer_free(&cert->certblob);
buffer_free(&cert->constraints);
if (cert->key_id != NULL)
xfree(cert->key_id);
for (i = 0; i < cert->nprincipals; i++)
xfree(cert->principals[i]);
if (cert->principals != NULL)
xfree(cert->principals);
if (cert->signature_key != NULL)
key_free(cert->signature_key);
}
void void
key_free(Key *k) key_free(Key *k)
{ {
@ -136,11 +184,13 @@ key_free(Key *k)
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
if (k->rsa != NULL) if (k->rsa != NULL)
RSA_free(k->rsa); RSA_free(k->rsa);
k->rsa = NULL; k->rsa = NULL;
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
if (k->dsa != NULL) if (k->dsa != NULL)
DSA_free(k->dsa); DSA_free(k->dsa);
k->dsa = NULL; k->dsa = NULL;
@ -151,20 +201,49 @@ key_free(Key *k)
fatal("key_free: bad key type %d", k->type); fatal("key_free: bad key type %d", k->type);
break; break;
} }
if (key_is_cert(k)) {
if (k->cert != NULL)
cert_free(k->cert);
k->cert = NULL;
}
xfree(k); xfree(k);
} }
int static int
key_equal(const Key *a, const Key *b) cert_compare(struct KeyCert *a, struct KeyCert *b)
{ {
if (a == NULL || b == NULL || a->type != b->type) if (a == NULL && b == NULL)
return 1;
if (a == NULL || b == NULL)
return 0; return 0;
if (buffer_len(&a->certblob) != buffer_len(&b->certblob))
return 0;
if (memcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob),
buffer_len(&a->certblob)) != 0)
return 0;
return 1;
}
/*
* Compare public portions of key only, allowing comparisons between
* certificates and plain keys too.
*/
int
key_equal_public(const Key *a, const Key *b)
{
if (a == NULL || b == NULL ||
key_type_plain(a->type) != key_type_plain(b->type))
return 0;
switch (a->type) { switch (a->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA_CERT:
case KEY_RSA: case KEY_RSA:
return a->rsa != NULL && b->rsa != NULL && return a->rsa != NULL && b->rsa != NULL &&
BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
BN_cmp(a->rsa->n, b->rsa->n) == 0; BN_cmp(a->rsa->n, b->rsa->n) == 0;
case KEY_DSA_CERT:
case KEY_DSA: case KEY_DSA:
return a->dsa != NULL && b->dsa != NULL && return a->dsa != NULL && b->dsa != NULL &&
BN_cmp(a->dsa->p, b->dsa->p) == 0 && BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
@ -177,16 +256,27 @@ key_equal(const Key *a, const Key *b)
/* NOTREACHED */ /* NOTREACHED */
} }
int
key_equal(const Key *a, const Key *b)
{
if (a == NULL || b == NULL || a->type != b->type)
return 0;
if (key_is_cert(a)) {
if (!cert_compare(a->cert, b->cert))
return 0;
}
return key_equal_public(a, b);
}
u_char* u_char*
key_fingerprint_raw(const Key *k, enum fp_type dgst_type, key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
u_int *dgst_raw_length)
{ {
const EVP_MD *md = NULL; const EVP_MD *md = NULL;
EVP_MD_CTX ctx; EVP_MD_CTX ctx;
u_char *blob = NULL; u_char *blob = NULL;
u_char *retval = NULL; u_char *retval = NULL;
u_int len = 0; u_int len = 0;
int nlen, elen; int nlen, elen, otype;
*dgst_raw_length = 0; *dgst_raw_length = 0;
@ -214,6 +304,14 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
case KEY_RSA: case KEY_RSA:
key_to_blob(k, &blob, &len); key_to_blob(k, &blob, &len);
break; break;
case KEY_DSA_CERT:
case KEY_RSA_CERT:
/* We want a fingerprint of the _key_ not of the cert */
otype = k->type;
k->type = key_type_plain(k->type);
key_to_blob(k, &blob, &len);
k->type = otype;
break;
case KEY_UNSPEC: case KEY_UNSPEC:
return retval; return retval;
default: default:
@ -408,7 +506,7 @@ key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)
} }
char * char *
key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
{ {
char *retval = NULL; char *retval = NULL;
u_char *dgst_raw; u_char *dgst_raw;
@ -522,11 +620,19 @@ key_read(Key *ret, char **cpp)
return -1; return -1;
if (!read_bignum(cpp, ret->rsa->n)) if (!read_bignum(cpp, ret->rsa->n))
return -1; return -1;
/* validate the claimed number of bits */
if ((u_int)BN_num_bits(ret->rsa->n) != bits) {
verbose("key_read: claimed key size %d does not match "
"actual %d", bits, BN_num_bits(ret->rsa->n));
return -1;
}
success = 1; success = 1;
break; break;
case KEY_UNSPEC: case KEY_UNSPEC:
case KEY_RSA: case KEY_RSA:
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
case KEY_RSA_CERT:
space = strchr(cp, ' '); space = strchr(cp, ' ');
if (space == NULL) { if (space == NULL) {
debug3("key_read: missing whitespace"); debug3("key_read: missing whitespace");
@ -571,25 +677,36 @@ key_read(Key *ret, char **cpp)
return -1; return -1;
} }
/*XXXX*/ /*XXXX*/
if (ret->type == KEY_RSA) { if (key_is_cert(ret)) {
if (!key_is_cert(k)) {
error("key_read: loaded key is not a cert");
key_free(k);
return -1;
}
if (ret->cert != NULL)
cert_free(ret->cert);
ret->cert = k->cert;
k->cert = NULL;
}
if (key_type_plain(ret->type) == KEY_RSA) {
if (ret->rsa != NULL) if (ret->rsa != NULL)
RSA_free(ret->rsa); RSA_free(ret->rsa);
ret->rsa = k->rsa; ret->rsa = k->rsa;
k->rsa = NULL; k->rsa = NULL;
success = 1;
#ifdef DEBUG_PK #ifdef DEBUG_PK
RSA_print_fp(stderr, ret->rsa, 8); RSA_print_fp(stderr, ret->rsa, 8);
#endif #endif
} else { }
if (key_type_plain(ret->type) == KEY_DSA) {
if (ret->dsa != NULL) if (ret->dsa != NULL)
DSA_free(ret->dsa); DSA_free(ret->dsa);
ret->dsa = k->dsa; ret->dsa = k->dsa;
k->dsa = NULL; k->dsa = NULL;
success = 1;
#ifdef DEBUG_PK #ifdef DEBUG_PK
DSA_print_fp(stderr, ret->dsa, 8); DSA_print_fp(stderr, ret->dsa, 8);
#endif #endif
} }
success = 1;
/*XXXX*/ /*XXXX*/
key_free(k); key_free(k);
if (success != 1) if (success != 1)
@ -616,28 +733,53 @@ key_write(const Key *key, FILE *f)
u_char *blob; u_char *blob;
char *uu; char *uu;
if (key->type == KEY_RSA1 && key->rsa != NULL) { if (key_is_cert(key)) {
if (key->cert == NULL) {
error("%s: no cert data", __func__);
return 0;
}
if (buffer_len(&key->cert->certblob) == 0) {
error("%s: no signed certificate blob", __func__);
return 0;
}
}
switch (key->type) {
case KEY_RSA1:
if (key->rsa == NULL)
return 0;
/* size of modulus 'n' */ /* size of modulus 'n' */
bits = BN_num_bits(key->rsa->n); bits = BN_num_bits(key->rsa->n);
fprintf(f, "%u", bits); fprintf(f, "%u", bits);
if (write_bignum(f, key->rsa->e) && if (write_bignum(f, key->rsa->e) &&
write_bignum(f, key->rsa->n)) { write_bignum(f, key->rsa->n))
success = 1; return 1;
} else { error("key_write: failed for RSA key");
error("key_write: failed for RSA key"); return 0;
} case KEY_DSA:
} else if ((key->type == KEY_DSA && key->dsa != NULL) || case KEY_DSA_CERT:
(key->type == KEY_RSA && key->rsa != NULL)) { if (key->dsa == NULL)
key_to_blob(key, &blob, &len); return 0;
uu = xmalloc(2*len); break;
n = uuencode(blob, len, uu, 2*len); case KEY_RSA:
if (n > 0) { case KEY_RSA_CERT:
fprintf(f, "%s %s", key_ssh_name(key), uu); if (key->rsa == NULL)
success = 1; return 0;
} break;
xfree(blob); default:
xfree(uu); return 0;
} }
key_to_blob(key, &blob, &len);
uu = xmalloc(2*len);
n = uuencode(blob, len, uu, 2*len);
if (n > 0) {
fprintf(f, "%s %s", key_ssh_name(key), uu);
success = 1;
}
xfree(blob);
xfree(uu);
return success; return success;
} }
@ -651,6 +793,10 @@ key_type(const Key *k)
return "RSA"; return "RSA";
case KEY_DSA: case KEY_DSA:
return "DSA"; return "DSA";
case KEY_RSA_CERT:
return "RSA-CERT";
case KEY_DSA_CERT:
return "DSA-CERT";
} }
return "unknown"; return "unknown";
} }
@ -663,6 +809,10 @@ key_ssh_name(const Key *k)
return "ssh-rsa"; return "ssh-rsa";
case KEY_DSA: case KEY_DSA:
return "ssh-dss"; return "ssh-dss";
case KEY_RSA_CERT:
return "ssh-rsa-cert-v00@openssh.com";
case KEY_DSA_CERT:
return "ssh-dss-cert-v00@openssh.com";
} }
return "ssh-unknown"; return "ssh-unknown";
} }
@ -673,8 +823,10 @@ key_size(const Key *k)
switch (k->type) { switch (k->type) {
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
return BN_num_bits(k->rsa->n); return BN_num_bits(k->rsa->n);
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
return BN_num_bits(k->dsa->p); return BN_num_bits(k->dsa->p);
} }
return 0; return 0;
@ -685,7 +837,7 @@ rsa_generate_private_key(u_int bits)
{ {
RSA *private; RSA *private;
private = RSA_generate_key(bits, 35, NULL, NULL); private = RSA_generate_key(bits, RSA_F4, NULL, NULL);
if (private == NULL) if (private == NULL)
fatal("rsa_generate_private_key: key generation failed."); fatal("rsa_generate_private_key: key generation failed.");
return private; return private;
@ -717,6 +869,9 @@ key_generate(int type, u_int bits)
case KEY_RSA1: case KEY_RSA1:
k->rsa = rsa_generate_private_key(bits); k->rsa = rsa_generate_private_key(bits);
break; break;
case KEY_RSA_CERT:
case KEY_DSA_CERT:
fatal("key_generate: cert keys cannot be generated directly");
default: default:
fatal("key_generate: unknown type %d", type); fatal("key_generate: unknown type %d", type);
} }
@ -724,12 +879,55 @@ key_generate(int type, u_int bits)
return k; return k;
} }
void
key_cert_copy(const Key *from_key, struct Key *to_key)
{
u_int i;
const struct KeyCert *from;
struct KeyCert *to;
if (to_key->cert != NULL) {
cert_free(to_key->cert);
to_key->cert = NULL;
}
if ((from = from_key->cert) == NULL)
return;
to = to_key->cert = cert_new();
buffer_append(&to->certblob, buffer_ptr(&from->certblob),
buffer_len(&from->certblob));
buffer_append(&to->constraints, buffer_ptr(&from->constraints),
buffer_len(&from->constraints));
to->type = from->type;
to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id);
to->valid_after = from->valid_after;
to->valid_before = from->valid_before;
to->signature_key = from->signature_key == NULL ?
NULL : key_from_private(from->signature_key);
to->nprincipals = from->nprincipals;
if (to->nprincipals > CERT_MAX_PRINCIPALS)
fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)",
__func__, to->nprincipals, CERT_MAX_PRINCIPALS);
if (to->nprincipals > 0) {
to->principals = xcalloc(from->nprincipals,
sizeof(*to->principals));
for (i = 0; i < to->nprincipals; i++)
to->principals[i] = xstrdup(from->principals[i]);
}
}
Key * Key *
key_from_private(const Key *k) key_from_private(const Key *k)
{ {
Key *n = NULL; Key *n = NULL;
switch (k->type) { switch (k->type) {
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
n = key_new(k->type); n = key_new(k->type);
if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
(BN_copy(n->dsa->q, k->dsa->q) == NULL) || (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
@ -739,6 +937,7 @@ key_from_private(const Key *k)
break; break;
case KEY_RSA: case KEY_RSA:
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA_CERT:
n = key_new(k->type); n = key_new(k->type);
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
(BN_copy(n->rsa->e, k->rsa->e) == NULL)) (BN_copy(n->rsa->e, k->rsa->e) == NULL))
@ -748,6 +947,8 @@ key_from_private(const Key *k)
fatal("key_from_private: unknown type %d", k->type); fatal("key_from_private: unknown type %d", k->type);
break; break;
} }
if (key_is_cert(k))
key_cert_copy(k, n);
return n; return n;
} }
@ -764,6 +965,10 @@ key_type_from_name(char *name)
return KEY_RSA; return KEY_RSA;
} else if (strcmp(name, "ssh-dss") == 0) { } else if (strcmp(name, "ssh-dss") == 0) {
return KEY_DSA; return KEY_DSA;
} else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) {
return KEY_RSA_CERT;
} else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) {
return KEY_DSA_CERT;
} }
debug2("key_type_from_name: unknown key type '%s'", name); debug2("key_type_from_name: unknown key type '%s'", name);
return KEY_UNSPEC; return KEY_UNSPEC;
@ -791,6 +996,127 @@ key_names_valid2(const char *names)
return 1; return 1;
} }
static int
cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
{
u_char *principals, *constraints, *sig_key, *sig;
u_int signed_len, plen, clen, sklen, slen, kidlen;
Buffer tmp;
char *principal;
int ret = -1;
buffer_init(&tmp);
/* Copy the entire key blob for verification and later serialisation */
buffer_append(&key->cert->certblob, blob, blen);
principals = constraints = sig_key = sig = NULL;
if (buffer_get_int_ret(&key->cert->type, b) != 0 ||
(key->cert->key_id = buffer_get_string_ret(b, &kidlen)) == NULL ||
(principals = buffer_get_string_ret(b, &plen)) == NULL ||
buffer_get_int64_ret(&key->cert->valid_after, b) != 0 ||
buffer_get_int64_ret(&key->cert->valid_before, b) != 0 ||
(constraints = buffer_get_string_ret(b, &clen)) == NULL ||
/* skip nonce */ buffer_get_string_ptr_ret(b, NULL) == NULL ||
/* skip reserved */ buffer_get_string_ptr_ret(b, NULL) == NULL ||
(sig_key = buffer_get_string_ret(b, &sklen)) == NULL) {
error("%s: parse error", __func__);
goto out;
}
if (kidlen != strlen(key->cert->key_id)) {
error("%s: key ID contains \\0 character", __func__);
goto out;
}
/* Signature is left in the buffer so we can calculate this length */
signed_len = buffer_len(&key->cert->certblob) - buffer_len(b);
if ((sig = buffer_get_string_ret(b, &slen)) == NULL) {
error("%s: parse error", __func__);
goto out;
}
if (key->cert->type != SSH2_CERT_TYPE_USER &&
key->cert->type != SSH2_CERT_TYPE_HOST) {
error("Unknown certificate type %u", key->cert->type);
goto out;
}
buffer_append(&tmp, principals, plen);
while (buffer_len(&tmp) > 0) {
if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) {
error("%s: Too many principals", __func__);
goto out;
}
if ((principal = buffer_get_string_ret(&tmp, &plen)) == NULL) {
error("%s: Principals data invalid", __func__);
goto out;
}
if (strlen(principal) != plen) {
error("%s: Principal contains \\0 character",
__func__);
goto out;
}
key->cert->principals = xrealloc(key->cert->principals,
key->cert->nprincipals + 1, sizeof(*key->cert->principals));
key->cert->principals[key->cert->nprincipals++] = principal;
}
buffer_clear(&tmp);
buffer_append(&key->cert->constraints, constraints, clen);
buffer_append(&tmp, constraints, clen);
/* validate structure */
while (buffer_len(&tmp) != 0) {
if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
error("%s: Constraints data invalid", __func__);
goto out;
}
}
buffer_clear(&tmp);
if ((key->cert->signature_key = key_from_blob(sig_key,
sklen)) == NULL) {
error("%s: Signature key invalid", __func__);
goto out;
}
if (key->cert->signature_key->type != KEY_RSA &&
key->cert->signature_key->type != KEY_DSA) {
error("%s: Invalid signature key type %s (%d)", __func__,
key_type(key->cert->signature_key),
key->cert->signature_key->type);
goto out;
}
switch (key_verify(key->cert->signature_key, sig, slen,
buffer_ptr(&key->cert->certblob), signed_len)) {
case 1:
ret = 0;
break; /* Good signature */
case 0:
error("%s: Invalid signature on certificate", __func__);
goto out;
case -1:
error("%s: Certificate signature verification failed",
__func__);
goto out;
}
out:
buffer_free(&tmp);
if (principals != NULL)
xfree(principals);
if (constraints != NULL)
xfree(constraints);
if (sig_key != NULL)
xfree(sig_key);
if (sig != NULL)
xfree(sig);
return ret;
}
Key * Key *
key_from_blob(const u_char *blob, u_int blen) key_from_blob(const u_char *blob, u_int blen)
{ {
@ -813,10 +1139,12 @@ key_from_blob(const u_char *blob, u_int blen)
switch (type) { switch (type) {
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
key = key_new(type); key = key_new(type);
if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 || if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 ||
buffer_get_bignum2_ret(&b, key->rsa->n) == -1) { buffer_get_bignum2_ret(&b, key->rsa->n) == -1) {
error("key_from_blob: can't read rsa key"); error("key_from_blob: can't read rsa key");
badkey:
key_free(key); key_free(key);
key = NULL; key = NULL;
goto out; goto out;
@ -826,15 +1154,14 @@ key_from_blob(const u_char *blob, u_int blen)
#endif #endif
break; break;
case KEY_DSA: case KEY_DSA:
case KEY_DSA_CERT:
key = key_new(type); key = key_new(type);
if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 || if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 ||
buffer_get_bignum2_ret(&b, key->dsa->q) == -1 || buffer_get_bignum2_ret(&b, key->dsa->q) == -1 ||
buffer_get_bignum2_ret(&b, key->dsa->g) == -1 || buffer_get_bignum2_ret(&b, key->dsa->g) == -1 ||
buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) { buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) {
error("key_from_blob: can't read dsa key"); error("key_from_blob: can't read dsa key");
key_free(key); goto badkey;
key = NULL;
goto out;
} }
#ifdef DEBUG_PK #ifdef DEBUG_PK
DSA_print_fp(stderr, key->dsa, 8); DSA_print_fp(stderr, key->dsa, 8);
@ -847,6 +1174,10 @@ key_from_blob(const u_char *blob, u_int blen)
error("key_from_blob: cannot handle type %s", ktype); error("key_from_blob: cannot handle type %s", ktype);
goto out; goto out;
} }
if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) {
error("key_from_blob: can't parse cert data");
goto badkey;
}
rlen = buffer_len(&b); rlen = buffer_len(&b);
if (key != NULL && rlen != 0) if (key != NULL && rlen != 0)
error("key_from_blob: remaining bytes in key blob %d", rlen); error("key_from_blob: remaining bytes in key blob %d", rlen);
@ -869,6 +1200,12 @@ key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
} }
buffer_init(&b); buffer_init(&b);
switch (key->type) { switch (key->type) {
case KEY_DSA_CERT:
case KEY_RSA_CERT:
/* Use the existing blob */
buffer_append(&b, buffer_ptr(&key->cert->certblob),
buffer_len(&key->cert->certblob));
break;
case KEY_DSA: case KEY_DSA:
buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_cstring(&b, key_ssh_name(key));
buffer_put_bignum2(&b, key->dsa->p); buffer_put_bignum2(&b, key->dsa->p);
@ -905,8 +1242,10 @@ key_sign(
const u_char *data, u_int datalen) const u_char *data, u_int datalen)
{ {
switch (key->type) { switch (key->type) {
case KEY_DSA_CERT:
case KEY_DSA: case KEY_DSA:
return ssh_dss_sign(key, sigp, lenp, data, datalen); return ssh_dss_sign(key, sigp, lenp, data, datalen);
case KEY_RSA_CERT:
case KEY_RSA: case KEY_RSA:
return ssh_rsa_sign(key, sigp, lenp, data, datalen); return ssh_rsa_sign(key, sigp, lenp, data, datalen);
default: default:
@ -929,8 +1268,10 @@ key_verify(
return -1; return -1;
switch (key->type) { switch (key->type) {
case KEY_DSA_CERT:
case KEY_DSA: case KEY_DSA:
return ssh_dss_verify(key, signature, signaturelen, data, datalen); return ssh_dss_verify(key, signature, signaturelen, data, datalen);
case KEY_RSA_CERT:
case KEY_RSA: case KEY_RSA:
return ssh_rsa_verify(key, signature, signaturelen, data, datalen); return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
default: default:
@ -952,6 +1293,9 @@ key_demote(const Key *k)
pk->rsa = NULL; pk->rsa = NULL;
switch (k->type) { switch (k->type) {
case KEY_RSA_CERT:
key_cert_copy(k, pk);
/* FALLTHROUGH */
case KEY_RSA1: case KEY_RSA1:
case KEY_RSA: case KEY_RSA:
if ((pk->rsa = RSA_new()) == NULL) if ((pk->rsa = RSA_new()) == NULL)
@ -961,6 +1305,9 @@ key_demote(const Key *k)
if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL)
fatal("key_demote: BN_dup failed"); fatal("key_demote: BN_dup failed");
break; break;
case KEY_DSA_CERT:
key_cert_copy(k, pk);
/* FALLTHROUGH */
case KEY_DSA: case KEY_DSA:
if ((pk->dsa = DSA_new()) == NULL) if ((pk->dsa = DSA_new()) == NULL)
fatal("key_demote: DSA_new failed"); fatal("key_demote: DSA_new failed");
@ -980,3 +1327,199 @@ key_demote(const Key *k)
return (pk); return (pk);
} }
int
key_is_cert(const Key *k)
{
return k != NULL &&
(k->type == KEY_RSA_CERT || k->type == KEY_DSA_CERT);
}
/* Return the cert-less equivalent to a certified key type */
int
key_type_plain(int type)
{
switch (type) {
case KEY_RSA_CERT:
return KEY_RSA;
case KEY_DSA_CERT:
return KEY_DSA;
default:
return type;
}
}
/* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */
int
key_to_certified(Key *k)
{
switch (k->type) {
case KEY_RSA:
k->cert = cert_new();
k->type = KEY_RSA_CERT;
return 0;
case KEY_DSA:
k->cert = cert_new();
k->type = KEY_DSA_CERT;
return 0;
default:
error("%s: key has incorrect type %s", __func__, key_type(k));
return -1;
}
}
/* Convert a KEY_RSA_CERT or KEY_DSA_CERT to their raw key equivalent */
int
key_drop_cert(Key *k)
{
switch (k->type) {
case KEY_RSA_CERT:
cert_free(k->cert);
k->type = KEY_RSA;
return 0;
case KEY_DSA_CERT:
cert_free(k->cert);
k->type = KEY_DSA;
return 0;
default:
error("%s: key has incorrect type %s", __func__, key_type(k));
return -1;
}
}
/* Sign a KEY_RSA_CERT or KEY_DSA_CERT, (re-)generating the signed certblob */
int
key_certify(Key *k, Key *ca)
{
Buffer principals;
u_char *ca_blob, *sig_blob, nonce[32];
u_int i, ca_len, sig_len;
if (k->cert == NULL) {
error("%s: key lacks cert info", __func__);
return -1;
}
if (!key_is_cert(k)) {
error("%s: certificate has unknown type %d", __func__,
k->cert->type);
return -1;
}
if (ca->type != KEY_RSA && ca->type != KEY_DSA) {
error("%s: CA key has unsupported type %s", __func__,
key_type(ca));
return -1;
}
key_to_blob(ca, &ca_blob, &ca_len);
buffer_clear(&k->cert->certblob);
buffer_put_cstring(&k->cert->certblob, key_ssh_name(k));
switch (k->type) {
case KEY_DSA_CERT:
buffer_put_bignum2(&k->cert->certblob, k->dsa->p);
buffer_put_bignum2(&k->cert->certblob, k->dsa->q);
buffer_put_bignum2(&k->cert->certblob, k->dsa->g);
buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key);
break;
case KEY_RSA_CERT:
buffer_put_bignum2(&k->cert->certblob, k->rsa->e);
buffer_put_bignum2(&k->cert->certblob, k->rsa->n);
break;
default:
error("%s: key has incorrect type %s", __func__, key_type(k));
buffer_clear(&k->cert->certblob);
xfree(ca_blob);
return -1;
}
buffer_put_int(&k->cert->certblob, k->cert->type);
buffer_put_cstring(&k->cert->certblob, k->cert->key_id);
buffer_init(&principals);
for (i = 0; i < k->cert->nprincipals; i++)
buffer_put_cstring(&principals, k->cert->principals[i]);
buffer_put_string(&k->cert->certblob, buffer_ptr(&principals),
buffer_len(&principals));
buffer_free(&principals);
buffer_put_int64(&k->cert->certblob, k->cert->valid_after);
buffer_put_int64(&k->cert->certblob, k->cert->valid_before);
buffer_put_string(&k->cert->certblob,
buffer_ptr(&k->cert->constraints),
buffer_len(&k->cert->constraints));
arc4random_buf(&nonce, sizeof(nonce));
buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */
buffer_put_string(&k->cert->certblob, ca_blob, ca_len);
xfree(ca_blob);
/* Sign the whole mess */
if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob),
buffer_len(&k->cert->certblob)) != 0) {
error("%s: signature operation failed", __func__);
buffer_clear(&k->cert->certblob);
return -1;
}
/* Append signature and we are done */
buffer_put_string(&k->cert->certblob, sig_blob, sig_len);
xfree(sig_blob);
return 0;
}
int
key_cert_check_authority(const Key *k, int want_host, int require_principal,
const char *name, const char **reason)
{
u_int i, principal_matches;
time_t now = time(NULL);
if (want_host) {
if (k->cert->type != SSH2_CERT_TYPE_HOST) {
*reason = "Certificate invalid: not a host certificate";
return -1;
}
} else {
if (k->cert->type != SSH2_CERT_TYPE_USER) {
*reason = "Certificate invalid: not a user certificate";
return -1;
}
}
if (now < 0) {
error("%s: system clock lies before epoch", __func__);
*reason = "Certificate invalid: not yet valid";
return -1;
}
if ((u_int64_t)now < k->cert->valid_after) {
*reason = "Certificate invalid: not yet valid";
return -1;
}
if ((u_int64_t)now >= k->cert->valid_before) {
*reason = "Certificate invalid: expired";
return -1;
}
if (k->cert->nprincipals == 0) {
if (require_principal) {
*reason = "Certificate lacks principal list";
return -1;
}
} else {
principal_matches = 0;
for (i = 0; i < k->cert->nprincipals; i++) {
if (strcmp(name, k->cert->principals[i]) == 0) {
principal_matches = 1;
break;
}
}
if (!principal_matches) {
*reason = "Certificate invalid: name is not a listed "
"principal";
return -1;
}
}
return 0;
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: key.h,v 1.27 2008/06/11 21:01:35 grunk Exp $ */ /* $OpenBSD: key.h,v 1.28 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -26,6 +26,7 @@
#ifndef KEY_H #ifndef KEY_H
#define KEY_H #define KEY_H
#include "buffer.h"
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/dsa.h> #include <openssl/dsa.h>
@ -34,6 +35,8 @@ enum types {
KEY_RSA1, KEY_RSA1,
KEY_RSA, KEY_RSA,
KEY_DSA, KEY_DSA,
KEY_RSA_CERT,
KEY_DSA_CERT,
KEY_UNSPEC KEY_UNSPEC
}; };
enum fp_type { enum fp_type {
@ -49,20 +52,35 @@ enum fp_rep {
/* key is stored in external hardware */ /* key is stored in external hardware */
#define KEY_FLAG_EXT 0x0001 #define KEY_FLAG_EXT 0x0001
#define CERT_MAX_PRINCIPALS 256
struct KeyCert {
Buffer certblob; /* Kept around for use on wire */
u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
char *key_id;
u_int nprincipals;
char **principals;
u_int64_t valid_after, valid_before;
Buffer constraints;
Key *signature_key;
};
struct Key { struct Key {
int type; int type;
int flags; int flags;
RSA *rsa; RSA *rsa;
DSA *dsa; DSA *dsa;
struct KeyCert *cert;
}; };
Key *key_new(int); Key *key_new(int);
void key_add_private(Key *);
Key *key_new_private(int); Key *key_new_private(int);
void key_free(Key *); void key_free(Key *);
Key *key_demote(const Key *); Key *key_demote(const Key *);
int key_equal_public(const Key *, const Key *);
int key_equal(const Key *, const Key *); int key_equal(const Key *, const Key *);
char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); char *key_fingerprint(Key *, enum fp_type, enum fp_rep);
u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *);
const char *key_type(const Key *); const char *key_type(const Key *);
int key_write(const Key *, FILE *); int key_write(const Key *, FILE *);
int key_read(Key *, char **); int key_read(Key *, char **);
@ -71,6 +89,14 @@ u_int key_size(const Key *);
Key *key_generate(int, u_int); Key *key_generate(int, u_int);
Key *key_from_private(const Key *); Key *key_from_private(const Key *);
int key_type_from_name(char *); int key_type_from_name(char *);
int key_is_cert(const Key *);
int key_type_plain(int);
int key_to_certified(Key *);
int key_drop_cert(Key *);
int key_certify(Key *, Key *);
void key_cert_copy(const Key *, struct Key *);
int key_cert_check_authority(const Key *, int, int, const char *,
const char **);
Key *key_from_blob(const u_char *, u_int); Key *key_from_blob(const u_char *, u_int);
int key_to_blob(const Key *, u_char **, u_int *); int key_to_blob(const Key *, u_char **, u_int *);

View File

@ -1322,8 +1322,8 @@ wtmpx_write_entry(struct logininfo *li)
static int static int
wtmpx_islogin(struct logininfo *li, struct utmpx *utx) wtmpx_islogin(struct logininfo *li, struct utmpx *utx)
{ {
if (strncmp(li->username, utx->ut_name, if (strncmp(li->username, utx->ut_user,
MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) { MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) {
# ifdef HAVE_TYPE_IN_UTMPX # ifdef HAVE_TYPE_IN_UTMPX
if (utx->ut_type == USER_PROCESS) if (utx->ut_type == USER_PROCESS)
return (1); return (1);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: match.h,v 1.14 2008/06/10 03:57:27 djm Exp $ */ /* $OpenBSD: match.h,v 1.15 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -23,5 +23,5 @@ char *match_list(const char *, const char *, u_int *);
/* addrmatch.c */ /* addrmatch.c */
int addr_match_list(const char *, const char *); int addr_match_list(const char *, const char *);
int addr_match_cidr_list(const char *, const char *);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.71 2009/02/21 19:32:04 tobias Exp $ */ /* $OpenBSD: misc.c,v 1.75 2010/01/09 23:04:13 dtucker Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@ -560,11 +560,11 @@ char *
percent_expand(const char *string, ...) percent_expand(const char *string, ...)
{ {
#define EXPAND_MAX_KEYS 16 #define EXPAND_MAX_KEYS 16
u_int num_keys, i, j;
struct { struct {
const char *key; const char *key;
const char *repl; const char *repl;
} keys[EXPAND_MAX_KEYS]; } keys[EXPAND_MAX_KEYS];
u_int num_keys, i, j;
char buf[4096]; char buf[4096];
va_list ap; va_list ap;
@ -576,13 +576,12 @@ percent_expand(const char *string, ...)
break; break;
keys[num_keys].repl = va_arg(ap, char *); keys[num_keys].repl = va_arg(ap, char *);
if (keys[num_keys].repl == NULL) if (keys[num_keys].repl == NULL)
fatal("percent_expand: NULL replacement"); fatal("%s: NULL replacement", __func__);
} }
if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
fatal("%s: too many keys", __func__);
va_end(ap); va_end(ap);
if (num_keys >= EXPAND_MAX_KEYS)
fatal("percent_expand: too many keys");
/* Expand string */ /* Expand string */
*buf = '\0'; *buf = '\0';
for (i = 0; *string != '\0'; string++) { for (i = 0; *string != '\0'; string++) {
@ -590,23 +589,24 @@ percent_expand(const char *string, ...)
append: append:
buf[i++] = *string; buf[i++] = *string;
if (i >= sizeof(buf)) if (i >= sizeof(buf))
fatal("percent_expand: string too long"); fatal("%s: string too long", __func__);
buf[i] = '\0'; buf[i] = '\0';
continue; continue;
} }
string++; string++;
/* %% case */
if (*string == '%') if (*string == '%')
goto append; goto append;
for (j = 0; j < num_keys; j++) { for (j = 0; j < num_keys; j++) {
if (strchr(keys[j].key, *string) != NULL) { if (strchr(keys[j].key, *string) != NULL) {
i = strlcat(buf, keys[j].repl, sizeof(buf)); i = strlcat(buf, keys[j].repl, sizeof(buf));
if (i >= sizeof(buf)) if (i >= sizeof(buf))
fatal("percent_expand: string too long"); fatal("%s: string too long", __func__);
break; break;
} }
} }
if (j >= num_keys) if (j >= num_keys)
fatal("percent_expand: unknown key %%%c", *string); fatal("%s: unknown key %%%c", __func__, *string);
} }
return (xstrdup(buf)); return (xstrdup(buf));
#undef EXPAND_MAX_KEYS #undef EXPAND_MAX_KEYS
@ -849,3 +849,14 @@ ms_to_timeval(struct timeval *tv, int ms)
tv->tv_usec = (ms % 1000) * 1000; tv->tv_usec = (ms % 1000) * 1000;
} }
void
sock_set_v6only(int s)
{
#ifdef IPV6_V6ONLY
int on = 1;
debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
#endif
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.38 2008/06/12 20:38:28 dtucker Exp $ */ /* $OpenBSD: misc.h,v 1.41 2010/01/09 23:04:13 dtucker Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -35,6 +35,7 @@ char *tohex(const void *, size_t);
void sanitise_stdfd(void); void sanitise_stdfd(void);
void ms_subtract_diff(struct timeval *, int *); void ms_subtract_diff(struct timeval *, int *);
void ms_to_timeval(struct timeval *, int); void ms_to_timeval(struct timeval *, int);
void sock_set_v6only(int);
struct passwd *pwcopy(struct passwd *); struct passwd *pwcopy(struct passwd *);
const char *ssh_gai_strerror(int); const char *ssh_gai_strerror(int);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.104 2009/06/12 20:43:22 andreas Exp $ */ /* $OpenBSD: monitor.c,v 1.106 2010/03/07 11:57:13 dtucker Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org> * Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -997,17 +997,6 @@ mm_answer_pam_free_ctx(int sock, Buffer *m)
} }
#endif #endif
static void
mm_append_debug(Buffer *m)
{
if (auth_debug_init && buffer_len(&auth_debug)) {
debug3("%s: Appending debug messages for child", __func__);
buffer_append(m, buffer_ptr(&auth_debug),
buffer_len(&auth_debug));
buffer_clear(&auth_debug);
}
}
int int
mm_answer_keyallowed(int sock, Buffer *m) mm_answer_keyallowed(int sock, Buffer *m)
{ {
@ -1090,8 +1079,6 @@ mm_answer_keyallowed(int sock, Buffer *m)
buffer_put_int(m, allowed); buffer_put_int(m, allowed);
buffer_put_int(m, forced_command != NULL); buffer_put_int(m, forced_command != NULL);
mm_append_debug(m);
mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m);
if (type == MM_RSAHOSTKEY) if (type == MM_RSAHOSTKEY)
@ -1475,8 +1462,6 @@ mm_answer_rsa_keyallowed(int sock, Buffer *m)
if (key != NULL) if (key != NULL)
key_free(key); key_free(key);
mm_append_debug(m);
mm_request_send(sock, MONITOR_ANS_RSAKEYALLOWED, m); mm_request_send(sock, MONITOR_ANS_RSAKEYALLOWED, m);
monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed);
@ -1721,7 +1706,8 @@ mm_get_kex(Buffer *m)
kex->flags = buffer_get_int(m); kex->flags = buffer_get_int(m);
kex->client_version_string = buffer_get_string(m, NULL); kex->client_version_string = buffer_get_string(m, NULL);
kex->server_version_string = buffer_get_string(m, NULL); kex->server_version_string = buffer_get_string(m, NULL);
kex->load_host_key=&get_hostkey_by_type; kex->load_host_public_key=&get_hostkey_public_by_type;
kex->load_host_private_key=&get_hostkey_private_by_type;
kex->host_key_index=&get_hostkey_index; kex->host_key_index=&get_hostkey_index;
return (kex); return (kex);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor_fdpass.c,v 1.18 2008/11/30 11:59:26 dtucker Exp $ */ /* $OpenBSD: monitor_fdpass.c,v 1.19 2010/01/12 00:58:25 djm Exp $ */
/* /*
* Copyright 2001 Niels Provos <provos@citi.umich.edu> * Copyright 2001 Niels Provos <provos@citi.umich.edu>
* All rights reserved. * All rights reserved.
@ -34,6 +34,9 @@
#endif #endif
#include <errno.h> #include <errno.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
@ -55,6 +58,7 @@ mm_send_fd(int sock, int fd)
struct iovec vec; struct iovec vec;
char ch = '\0'; char ch = '\0';
ssize_t n; ssize_t n;
struct pollfd pfd;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR #ifdef HAVE_ACCRIGHTS_IN_MSGHDR
@ -75,9 +79,13 @@ mm_send_fd(int sock, int fd)
msg.msg_iov = &vec; msg.msg_iov = &vec;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
while ((n = sendmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN || pfd.fd = sock;
errno == EINTR)) pfd.events = POLLOUT;
while ((n = sendmsg(sock, &msg, 0)) == -1 &&
(errno == EAGAIN || errno == EINTR)) {
debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno)); debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno));
(void)poll(&pfd, 1, -1);
}
if (n == -1) { if (n == -1) {
error("%s: sendmsg(%d): %s", __func__, fd, error("%s: sendmsg(%d): %s", __func__, fd,
strerror(errno)); strerror(errno));
@ -112,6 +120,7 @@ mm_receive_fd(int sock)
ssize_t n; ssize_t n;
char ch; char ch;
int fd; int fd;
struct pollfd pfd;
memset(&msg, 0, sizeof(msg)); memset(&msg, 0, sizeof(msg));
vec.iov_base = &ch; vec.iov_base = &ch;
@ -126,9 +135,13 @@ mm_receive_fd(int sock)
msg.msg_controllen = sizeof(cmsgbuf.buf); msg.msg_controllen = sizeof(cmsgbuf.buf);
#endif #endif
while ((n = recvmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN || pfd.fd = sock;
errno == EINTR)) pfd.events = POLLIN;
while ((n = recvmsg(sock, &msg, 0)) == -1 &&
(errno == EAGAIN || errno == EINTR)) {
debug3("%s: recvmsg: %s", __func__, strerror(errno)); debug3("%s: recvmsg: %s", __func__, strerror(errno));
(void)poll(&pfd, 1, -1);
}
if (n == -1) { if (n == -1) {
error("%s: recvmsg: %s", __func__, strerror(errno)); error("%s: recvmsg: %s", __func__, strerror(errno));
return -1; return -1;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor_wrap.c,v 1.68 2009/06/22 05:39:28 dtucker Exp $ */ /* $OpenBSD: monitor_wrap.c,v 1.69 2010/03/07 11:57:13 dtucker Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org> * Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -347,19 +347,6 @@ mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
return (ret); return (ret);
} }
static void
mm_send_debug(Buffer *m)
{
char *msg;
while (buffer_len(m)) {
msg = buffer_get_string(m, NULL);
debug3("%s: Sending debug: %s", __func__, msg);
packet_send_debug("%s", msg);
xfree(msg);
}
}
int int
mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key)
{ {
@ -393,9 +380,6 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key)
have_forced = buffer_get_int(&m); have_forced = buffer_get_int(&m);
forced_command = have_forced ? xstrdup("true") : NULL; forced_command = have_forced ? xstrdup("true") : NULL;
/* Send potential debug messages */
mm_send_debug(&m);
buffer_free(&m); buffer_free(&m);
return (allowed); return (allowed);
@ -1085,7 +1069,6 @@ mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
*rkey = key; *rkey = key;
xfree(blob); xfree(blob);
} }
mm_send_debug(&m);
buffer_free(&m); buffer_free(&m);
return (allowed); return (allowed);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $OpenBSD: myproposal.h,v 1.23 2009/01/23 07:58:11 djm Exp $ */ /* $OpenBSD: myproposal.h,v 1.24 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -40,7 +40,9 @@
"diffie-hellman-group1-sha1" "diffie-hellman-group1-sha1"
#endif #endif
#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" #define KEX_DEFAULT_PK_ALG "ssh-rsa-cert-v00@openssh.com," \
"ssh-dss-cert-v00@openssh.com," \
"ssh-rsa,ssh-dss"
#define KEX_DEFAULT_ENCRYPT \ #define KEX_DEFAULT_ENCRYPT \
"aes128-ctr,aes192-ctr,aes256-ctr," \ "aes128-ctr,aes192-ctr,aes256-ctr," \

View File

@ -1,4 +1,4 @@
/* $OpenBSD: nchan.c,v 1.62 2008/11/07 18:50:18 stevesk Exp $ */ /* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */
/* /*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
* *
@ -161,7 +161,7 @@ chan_ibuf_empty(Channel *c)
switch (c->istate) { switch (c->istate) {
case CHAN_INPUT_WAIT_DRAIN: case CHAN_INPUT_WAIT_DRAIN:
if (compat20) { if (compat20) {
if (!(c->flags & CHAN_CLOSE_SENT)) if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
chan_send_eof2(c); chan_send_eof2(c);
chan_set_istate(c, CHAN_INPUT_CLOSED); chan_set_istate(c, CHAN_INPUT_CLOSED);
} else { } else {
@ -278,9 +278,12 @@ static void
chan_rcvd_close2(Channel *c) chan_rcvd_close2(Channel *c)
{ {
debug2("channel %d: rcvd close", c->self); debug2("channel %d: rcvd close", c->self);
if (c->flags & CHAN_CLOSE_RCVD) if (!(c->flags & CHAN_LOCAL)) {
error("channel %d: protocol error: close rcvd twice", c->self); if (c->flags & CHAN_CLOSE_RCVD)
c->flags |= CHAN_CLOSE_RCVD; error("channel %d: protocol error: close rcvd twice",
c->self);
c->flags |= CHAN_CLOSE_RCVD;
}
if (c->type == SSH_CHANNEL_LARVAL) { if (c->type == SSH_CHANNEL_LARVAL) {
/* tear down larval channels immediately */ /* tear down larval channels immediately */
chan_set_ostate(c, CHAN_OUTPUT_CLOSED); chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
@ -302,11 +305,13 @@ chan_rcvd_close2(Channel *c)
chan_set_istate(c, CHAN_INPUT_CLOSED); chan_set_istate(c, CHAN_INPUT_CLOSED);
break; break;
case CHAN_INPUT_WAIT_DRAIN: case CHAN_INPUT_WAIT_DRAIN:
chan_send_eof2(c); if (!(c->flags & CHAN_LOCAL))
chan_send_eof2(c);
chan_set_istate(c, CHAN_INPUT_CLOSED); chan_set_istate(c, CHAN_INPUT_CLOSED);
break; break;
} }
} }
void void
chan_rcvd_eow(Channel *c) chan_rcvd_eow(Channel *c)
{ {
@ -454,6 +459,10 @@ chan_is_dead(Channel *c, int do_send)
c->self, c->efd, buffer_len(&c->extended)); c->self, c->efd, buffer_len(&c->extended));
return 0; return 0;
} }
if (c->flags & CHAN_LOCAL) {
debug2("channel %d: is dead (local)", c->self);
return 1;
}
if (!(c->flags & CHAN_CLOSE_SENT)) { if (!(c->flags & CHAN_CLOSE_SENT)) {
if (do_send) { if (do_send) {
chan_send_close2(c); chan_send_close2(c);

View File

@ -85,23 +85,14 @@ static struct wenv {
size_t namelen; size_t namelen;
} wenv_arr[] = { } wenv_arr[] = {
{ NL("ALLUSERSPROFILE=") }, { NL("ALLUSERSPROFILE=") },
{ NL("COMMONPROGRAMFILES=") },
{ NL("COMPUTERNAME=") }, { NL("COMPUTERNAME=") },
{ NL("COMSPEC=") }, { NL("COMSPEC=") },
{ NL("CYGWIN=") }, { NL("CYGWIN=") },
{ NL("NUMBER_OF_PROCESSORS=") },
{ NL("OS=") }, { NL("OS=") },
{ NL("PATH=") }, { NL("PATH=") },
{ NL("PATHEXT=") }, { NL("PATHEXT=") },
{ NL("PROCESSOR_ARCHITECTURE=") },
{ NL("PROCESSOR_IDENTIFIER=") },
{ NL("PROCESSOR_LEVEL=") },
{ NL("PROCESSOR_REVISION=") },
{ NL("PROGRAMFILES=") },
{ NL("SYSTEMDRIVE=") }, { NL("SYSTEMDRIVE=") },
{ NL("SYSTEMROOT=") }, { NL("SYSTEMROOT=") },
{ NL("TMP=") },
{ NL("TEMP=") },
{ NL("WINDIR=") } { NL("WINDIR=") }
}; };

View File

@ -1,4 +1,4 @@
/* $Id: openbsd-compat.h,v 1.46 2008/06/08 17:32:29 dtucker Exp $ */ /* $Id: openbsd-compat.h,v 1.49 2010/01/16 12:58:37 dtucker Exp $ */
/* /*
* Copyright (c) 1999-2003 Damien Miller. All rights reserved. * Copyright (c) 1999-2003 Damien Miller. All rights reserved.
@ -200,6 +200,14 @@ int vasprintf(char **, const char *, va_list);
int vsnprintf(char *, size_t, const char *, va_list); int vsnprintf(char *, size_t, const char *, va_list);
#endif #endif
#ifndef HAVE_USER_FROM_UID
char *user_from_uid(uid_t, int);
#endif
#ifndef HAVE_GROUP_FROM_GID
char *group_from_gid(gid_t, int);
#endif
void *xmmap(size_t size); void *xmmap(size_t size);
char *xcrypt(const char *password, const char *salt); char *xcrypt(const char *password, const char *salt);
char *shadow_pw(struct passwd *pw); char *shadow_pw(struct passwd *pw);

View File

@ -1,4 +1,4 @@
/* $Id: openssl-compat.c,v 1.8 2009/03/07 11:22:35 dtucker Exp $ */ /* $Id: openssl-compat.c,v 1.9 2010/01/28 23:54:11 dtucker Exp $ */
/* /*
* Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au> * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
@ -67,5 +67,6 @@ ssh_SSLeay_add_all_algorithms(void)
/* Enable use of crypto hardware */ /* Enable use of crypto hardware */
ENGINE_load_builtin_engines(); ENGINE_load_builtin_engines();
ENGINE_register_all_complete(); ENGINE_register_all_complete();
OPENSSL_config(NULL);
} }
#endif #endif

View File

@ -374,6 +374,31 @@ aix_restoreauthdb(void)
# endif /* WITH_AIXAUTHENTICATE */ # endif /* WITH_AIXAUTHENTICATE */
# ifdef USE_AIX_KRB_NAME
/*
* aix_krb5_get_principal_name: returns the user's kerberos client principal name if
* configured, otherwise NULL. Caller must free returned string.
*/
char *
aix_krb5_get_principal_name(char *pw_name)
{
char *authname = NULL, *authdomain = NULL, *principal = NULL;
setuserdb(S_READ);
if (getuserattr(pw_name, S_AUTHDOMAIN, &authdomain, SEC_CHAR) != 0)
debug("AIX getuserattr S_AUTHDOMAIN: %s", strerror(errno));
if (getuserattr(pw_name, S_AUTHNAME, &authname, SEC_CHAR) != 0)
debug("AIX getuserattr S_AUTHNAME: %s", strerror(errno));
if (authdomain != NULL)
xasprintf(&principal, "%s@%s", authname ? authname : pw_name, authdomain);
else if (authname != NULL)
principal = xstrdup(authname);
enduserdb();
return principal;
}
# endif /* USE_AIX_KRB_NAME */
# if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO) # if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO)
# undef getnameinfo # undef getnameinfo
/* /*

View File

@ -1,4 +1,4 @@
/* $Id: port-aix.h,v 1.31 2009/08/20 06:20:50 dtucker Exp $ */ /* $Id: port-aix.h,v 1.32 2009/12/20 23:49:22 dtucker Exp $ */
/* /*
* *
@ -95,6 +95,10 @@ int sys_auth_record_login(const char *, const char *, const char *, Buffer *);
# define CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG # define CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
char *sys_auth_get_lastlogin_msg(const char *, uid_t); char *sys_auth_get_lastlogin_msg(const char *, uid_t);
# define CUSTOM_FAILED_LOGIN 1 # define CUSTOM_FAILED_LOGIN 1
# if defined(S_AUTHDOMAIN) && defined (S_AUTHNAME)
# define USE_AIX_KRB_NAME
char *aix_krb5_get_principal_name(char *);
# endif
#endif #endif
void aix_setauthdb(const char *); void aix_setauthdb(const char *);

View File

@ -1,4 +1,4 @@
/* $Id: port-linux.c,v 1.5 2008/03/26 20:27:21 dtucker Exp $ */ /* $Id: port-linux.c,v 1.8 2010/03/01 04:52:50 dtucker Exp $ */
/* /*
* Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com> * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com>
@ -23,14 +23,17 @@
#include "includes.h" #include "includes.h"
#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST)
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#ifdef WITH_SELINUX
#include "log.h" #include "log.h"
#include "xmalloc.h"
#include "port-linux.h" #include "port-linux.h"
#ifdef WITH_SELINUX
#include <selinux/selinux.h> #include <selinux/selinux.h>
#include <selinux/flask.h> #include <selinux/flask.h>
#include <selinux/get_context_list.h> #include <selinux/get_context_list.h>
@ -168,4 +171,95 @@ ssh_selinux_setup_pty(char *pwname, const char *tty)
freecon(user_ctx); freecon(user_ctx);
debug3("%s: done", __func__); debug3("%s: done", __func__);
} }
void
ssh_selinux_change_context(const char *newname)
{
int len, newlen;
char *oldctx, *newctx, *cx;
if (!ssh_selinux_enabled())
return;
if (getcon((security_context_t *)&oldctx) < 0) {
logit("%s: getcon failed with %s", __func__, strerror (errno));
return;
}
if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) ==
NULL) {
logit ("%s: unparseable context %s", __func__, oldctx);
return;
}
newlen = strlen(oldctx) + strlen(newname) + 1;
newctx = xmalloc(newlen);
len = cx - oldctx + 1;
memcpy(newctx, oldctx, len);
strlcpy(newctx + len, newname, newlen - len);
if ((cx = index(cx + 1, ':')))
strlcat(newctx, cx, newlen);
debug3("%s: setting context from '%s' to '%s'", __func__, oldctx,
newctx);
if (setcon(newctx) < 0)
logit("%s: setcon failed with %s", __func__, strerror (errno));
xfree(oldctx);
xfree(newctx);
}
#endif /* WITH_SELINUX */ #endif /* WITH_SELINUX */
#ifdef LINUX_OOM_ADJUST
#define OOM_ADJ_PATH "/proc/self/oom_adj"
/*
* The magic "don't kill me", as documented in eg:
* http://lxr.linux.no/#linux+v2.6.32/Documentation/filesystems/proc.txt
*/
#define OOM_ADJ_NOKILL -17
static int oom_adj_save = INT_MIN;
/*
* Tell the kernel's out-of-memory killer to avoid sshd.
* Returns the previous oom_adj value or zero.
*/
void
oom_adjust_setup(void)
{
FILE *fp;
debug3("%s", __func__);
if ((fp = fopen(OOM_ADJ_PATH, "r+")) != NULL) {
if (fscanf(fp, "%d", &oom_adj_save) != 1)
verbose("error reading %s: %s", OOM_ADJ_PATH, strerror(errno));
else {
rewind(fp);
if (fprintf(fp, "%d\n", OOM_ADJ_NOKILL) <= 0)
verbose("error writing %s: %s",
OOM_ADJ_PATH, strerror(errno));
else
verbose("Set %s from %d to %d",
OOM_ADJ_PATH, oom_adj_save, OOM_ADJ_NOKILL);
}
fclose(fp);
}
}
/* Restore the saved OOM adjustment */
void
oom_adjust_restore(void)
{
FILE *fp;
debug3("%s", __func__);
if (oom_adj_save == INT_MIN || (fp = fopen(OOM_ADJ_PATH, "w")) == NULL)
return;
if (fprintf(fp, "%d\n", oom_adj_save) <= 0)
verbose("error writing %s: %s", OOM_ADJ_PATH, strerror(errno));
else
verbose("Set %s to %d", OOM_ADJ_PATH, oom_adj_save);
fclose(fp);
return;
}
#endif /* LINUX_OOM_ADJUST */
#endif /* WITH_SELINUX || LINUX_OOM_ADJUST */

View File

@ -1,4 +1,4 @@
/* $Id: port-linux.h,v 1.2 2008/03/26 20:27:21 dtucker Exp $ */ /* $Id: port-linux.h,v 1.4 2009/12/08 02:39:48 dtucker Exp $ */
/* /*
* Copyright (c) 2006 Damien Miller <djm@openbsd.org> * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
@ -23,6 +23,12 @@
int ssh_selinux_enabled(void); int ssh_selinux_enabled(void);
void ssh_selinux_setup_pty(char *, const char *); void ssh_selinux_setup_pty(char *, const char *);
void ssh_selinux_setup_exec_context(char *); void ssh_selinux_setup_exec_context(char *);
void ssh_selinux_change_context(const char *);
#endif
#ifdef LINUX_OOM_ADJUST
void oom_adjust_restore(void);
void oom_adjust_setup(void);
#endif #endif
#endif /* ! _PORT_LINUX_H */ #endif /* ! _PORT_LINUX_H */

View File

@ -0,0 +1,114 @@
/* $OpenBSD: pwcache.c,v 1.9 2005/08/08 08:05:34 espie Exp $ */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. 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.
*/
/* OPENBSD ORIGINAL: lib/libc/gen/pwcache.c */
#include "includes.h"
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCACHE 64 /* power of 2 */
#define MASK (NCACHE - 1) /* bits to store with */
#ifndef HAVE_USER_FROM_UID
char *
user_from_uid(uid_t uid, int nouser)
{
static struct ncache {
uid_t uid;
char *name;
} c_uid[NCACHE];
static int pwopen;
static char nbuf[15]; /* 32 bits == 10 digits */
struct passwd *pw;
struct ncache *cp;
cp = c_uid + (uid & MASK);
if (cp->uid != uid || cp->name == NULL) {
if (pwopen == 0) {
#ifdef HAVE_SETPASSENT
setpassent(1);
#endif
pwopen = 1;
}
if ((pw = getpwuid(uid)) == NULL) {
if (nouser)
return (NULL);
(void)snprintf(nbuf, sizeof(nbuf), "%u", uid);
}
cp->uid = uid;
if (cp->name != NULL)
free(cp->name);
cp->name = strdup(pw ? pw->pw_name : nbuf);
}
return (cp->name);
}
#endif
#ifndef HAVE_GROUP_FROM_GID
char *
group_from_gid(gid_t gid, int nogroup)
{
static struct ncache {
gid_t gid;
char *name;
} c_gid[NCACHE];
static int gropen;
static char nbuf[15]; /* 32 bits == 10 digits */
struct group *gr;
struct ncache *cp;
cp = c_gid + (gid & MASK);
if (cp->gid != gid || cp->name == NULL) {
if (gropen == 0) {
#ifdef HAVE_SETGROUPENT
setgroupent(1);
#endif
gropen = 1;
}
if ((gr = getgrgid(gid)) == NULL) {
if (nogroup)
return (NULL);
(void)snprintf(nbuf, sizeof(nbuf), "%u", gid);
}
cp->gid = gid;
if (cp->name != NULL)
free(cp->name);
cp->name = strdup(gr ? gr->gr_name : nbuf);
}
return (cp->name);
}
#endif

View File

@ -1,7 +1,7 @@
/* $OpenBSD: readpassphrase.c,v 1.18 2005/08/08 08:05:34 espie Exp $ */ /* $OpenBSD: readpassphrase.c,v 1.22 2010/01/13 10:20:54 dtucker Exp $ */
/* /*
* Copyright (c) 2000-2002 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 2000-2002, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -46,7 +46,7 @@
# define _POSIX_VDISABLE VDISABLE # define _POSIX_VDISABLE VDISABLE
#endif #endif
static volatile sig_atomic_t signo; static volatile sig_atomic_t signo[_NSIG];
static void handler(int); static void handler(int);
@ -54,7 +54,7 @@ char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{ {
ssize_t nr; ssize_t nr;
int input, output, save_errno; int input, output, save_errno, i, need_restart;
char ch, *p, *end; char ch, *p, *end;
struct termios term, oterm; struct termios term, oterm;
struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
@ -67,7 +67,11 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
} }
restart: restart:
signo = 0; for (i = 0; i < _NSIG; i++)
signo[i] = 0;
nr = -1;
save_errno = 0;
need_restart = 0;
/* /*
* Read and write to /dev/tty if available. If not, read from * Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required. * stdin and write to stderr unless a tty is required.
@ -117,26 +121,30 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
oterm.c_lflag |= ECHO; oterm.c_lflag |= ECHO;
} }
if (!(flags & RPP_STDIN)) /* No I/O if we are already backgrounded. */
(void)write(output, prompt, strlen(prompt)); if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) {
end = buf + bufsiz - 1; if (!(flags & RPP_STDIN))
for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { (void)write(output, prompt, strlen(prompt));
if (p < end) { end = buf + bufsiz - 1;
if ((flags & RPP_SEVENBIT)) p = buf;
ch &= 0x7f; while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
if (isalpha(ch)) { if (p < end) {
if ((flags & RPP_FORCELOWER)) if ((flags & RPP_SEVENBIT))
ch = tolower(ch); ch &= 0x7f;
if ((flags & RPP_FORCEUPPER)) if (isalpha(ch)) {
ch = toupper(ch); if ((flags & RPP_FORCELOWER))
ch = (char)tolower(ch);
if ((flags & RPP_FORCEUPPER))
ch = (char)toupper(ch);
}
*p++ = ch;
} }
*p++ = ch;
} }
*p = '\0';
save_errno = errno;
if (!(term.c_lflag & ECHO))
(void)write(output, "\n", 1);
} }
*p = '\0';
save_errno = errno;
if (!(term.c_lflag & ECHO))
(void)write(output, "\n", 1);
/* Restore old terminal settings and signals. */ /* Restore old terminal settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0) { if (memcmp(&term, &oterm, sizeof(term)) != 0) {
@ -152,6 +160,7 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
(void)sigaction(SIGTERM, &saveterm, NULL); (void)sigaction(SIGTERM, &saveterm, NULL);
(void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTSTP, &savetstp, NULL);
(void)sigaction(SIGTTIN, &savettin, NULL); (void)sigaction(SIGTTIN, &savettin, NULL);
(void)sigaction(SIGTTOU, &savettou, NULL);
if (input != STDIN_FILENO) if (input != STDIN_FILENO)
(void)close(input); (void)close(input);
@ -159,20 +168,25 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
* If we were interrupted by a signal, resend it to ourselves * If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers. * now that we have restored the signal handlers.
*/ */
if (signo) { for (i = 0; i < _NSIG; i++) {
kill(getpid(), signo); if (signo[i]) {
switch (signo) { kill(getpid(), i);
case SIGTSTP: switch (i) {
case SIGTTIN: case SIGTSTP:
case SIGTTOU: case SIGTTIN:
goto restart; case SIGTTOU:
need_restart = 1;
}
} }
} }
if (need_restart)
goto restart;
errno = save_errno; if (save_errno)
errno = save_errno;
return(nr == -1 ? NULL : buf); return(nr == -1 ? NULL : buf);
} }
#if 0 #if 0
char * char *
getpass(const char *prompt) getpass(const char *prompt)
@ -186,6 +200,6 @@ getpass(const char *prompt)
static void handler(int s) static void handler(int s)
{ {
signo = s; signo[s] = 1;
} }
#endif /* HAVE_READPASSPHRASE */ #endif /* HAVE_READPASSPHRASE */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: pathnames.h,v 1.17 2008/12/29 02:23:26 stevesk Exp $ */ /* $OpenBSD: pathnames.h,v 1.19 2010/02/11 20:37:47 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -125,6 +125,11 @@
#define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign" #define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign"
#endif #endif
/* Location of ssh-pkcs11-helper to support keys in tokens */
#ifndef _PATH_SSH_PKCS11_HELPER
#define _PATH_SSH_PKCS11_HELPER "/usr/libexec/ssh-pkcs11-helper"
#endif
/* xauth for X11 forwarding */ /* xauth for X11 forwarding */
#ifndef _PATH_XAUTH #ifndef _PATH_XAUTH
#define _PATH_XAUTH "/usr/local/bin/xauth" #define _PATH_XAUTH "/usr/local/bin/xauth"

1357
crypto/openssh/pkcs11.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $Id: platform.c,v 1.1 2006/08/30 17:24:41 djm Exp $ */ /* $Id: platform.c,v 1.3 2009/12/20 23:49:22 dtucker Exp $ */
/* /*
* Copyright (c) 2006 Darren Tucker. All rights reserved. * Copyright (c) 2006 Darren Tucker. All rights reserved.
@ -21,6 +21,15 @@
#include "openbsd-compat/openbsd-compat.h" #include "openbsd-compat/openbsd-compat.h"
void
platform_pre_listen(void)
{
#ifdef LINUX_OOM_ADJUST
/* Adjust out-of-memory killer so listening process is not killed */
oom_adjust_setup();
#endif
}
void void
platform_pre_fork(void) platform_pre_fork(void)
{ {
@ -43,4 +52,17 @@ platform_post_fork_child(void)
#ifdef USE_SOLARIS_PROCESS_CONTRACTS #ifdef USE_SOLARIS_PROCESS_CONTRACTS
solaris_contract_post_fork_child(); solaris_contract_post_fork_child();
#endif #endif
#ifdef LINUX_OOM_ADJUST
oom_adjust_restore();
#endif
}
char *
platform_krb5_get_principal_name(const char *pw_name)
{
#ifdef USE_AIX_KRB_NAME
return aix_krb5_get_principal_name(pw_name);
#else
return NULL;
#endif
} }

View File

@ -1,4 +1,4 @@
/* $Id: platform.h,v 1.1 2006/08/30 17:24:41 djm Exp $ */ /* $Id: platform.h,v 1.4 2010/01/14 01:44:16 djm Exp $ */
/* /*
* Copyright (c) 2006 Darren Tucker. All rights reserved. * Copyright (c) 2006 Darren Tucker. All rights reserved.
@ -18,6 +18,11 @@
#include <sys/types.h> #include <sys/types.h>
void platform_pre_listen(void);
void platform_pre_fork(void); void platform_pre_fork(void);
void platform_post_fork_parent(pid_t child_pid); void platform_post_fork_parent(pid_t child_pid);
void platform_post_fork_child(void); void platform_post_fork_child(void);
char *platform_get_krb5_client(const char *);
char *platform_krb5_get_principal_name(const char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.177 2009/06/27 09:35:06 andreas Exp $ */ /* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -126,7 +126,7 @@ typedef enum {
oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
oClearAllForwardings, oNoHostAuthenticationForLocalhost, oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oGssAuthentication, oGssDelegateCreds, oAddressFamily, oGssAuthentication, oGssDelegateCreds,
@ -209,10 +209,12 @@ static struct {
{ "preferredauthentications", oPreferredAuthentications }, { "preferredauthentications", oPreferredAuthentications },
{ "hostkeyalgorithms", oHostKeyAlgorithms }, { "hostkeyalgorithms", oHostKeyAlgorithms },
{ "bindaddress", oBindAddress }, { "bindaddress", oBindAddress },
#ifdef SMARTCARD #ifdef ENABLE_PKCS11
{ "smartcarddevice", oSmartcardDevice }, { "smartcarddevice", oPKCS11Provider },
{ "pkcs11provider", oPKCS11Provider },
#else #else
{ "smartcarddevice", oUnsupported }, { "smartcarddevice", oUnsupported },
{ "pkcs11provider", oUnsupported },
#endif #endif
{ "clearallforwardings", oClearAllForwardings }, { "clearallforwardings", oClearAllForwardings },
{ "enablesshkeysign", oEnableSSHKeysign }, { "enablesshkeysign", oEnableSSHKeysign },
@ -626,8 +628,8 @@ process_config_line(Options *options, const char *host,
charptr = &options->bind_address; charptr = &options->bind_address;
goto parse_string; goto parse_string;
case oSmartcardDevice: case oPKCS11Provider:
charptr = &options->smartcard_device; charptr = &options->pkcs11_provider;
goto parse_string; goto parse_string;
case oProxyCommand: case oProxyCommand:
@ -1075,7 +1077,7 @@ initialize_options(Options * options)
options->log_level = SYSLOG_LEVEL_NOT_SET; options->log_level = SYSLOG_LEVEL_NOT_SET;
options->preferred_authentications = NULL; options->preferred_authentications = NULL;
options->bind_address = NULL; options->bind_address = NULL;
options->smartcard_device = NULL; options->pkcs11_provider = NULL;
options->enable_ssh_keysign = - 1; options->enable_ssh_keysign = - 1;
options->no_host_authentication_for_localhost = - 1; options->no_host_authentication_for_localhost = - 1;
options->identities_only = - 1; options->identities_only = - 1;
@ -1166,7 +1168,7 @@ fill_default_options(Options * options)
/* options->macs, default set in myproposals.h */ /* options->macs, default set in myproposals.h */
/* options->hostkeyalgorithms, default set in myproposals.h */ /* options->hostkeyalgorithms, default set in myproposals.h */
if (options->protocol == SSH_PROTO_UNKNOWN) if (options->protocol == SSH_PROTO_UNKNOWN)
options->protocol = SSH_PROTO_1|SSH_PROTO_2; options->protocol = SSH_PROTO_2;
if (options->num_identity_files == 0) { if (options->num_identity_files == 0) {
if (options->protocol & SSH_PROTO_1) { if (options->protocol & SSH_PROTO_1) {
len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.79 2009/06/27 09:35:06 andreas Exp $ */ /* $OpenBSD: readconf.h,v 1.82 2010/02/08 10:50:20 markus Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -84,7 +84,7 @@ typedef struct {
char *user_hostfile2; char *user_hostfile2;
char *preferred_authentications; char *preferred_authentications;
char *bind_address; /* local socket address for connection to sshd */ char *bind_address; /* local socket address for connection to sshd */
char *smartcard_device; /* Smartcard reader device */ char *pkcs11_provider; /* PKCS#11 provider */
int verify_host_key_dns; /* Verify host key using DNS */ int verify_host_key_dns; /* Verify host key using DNS */
int num_identity_files; /* Number of files for RSA/DSA identities. */ int num_identity_files; /* Number of files for RSA/DSA identities. */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: roaming.h,v 1.4 2009/06/27 09:32:43 andreas Exp $ */ /* $OpenBSD: roaming.h,v 1.5 2009/10/24 11:11:58 andreas Exp $ */
/* /*
* Copyright (c) 2004-2009 AppGate Network Security AB * Copyright (c) 2004-2009 AppGate Network Security AB
* *
@ -19,12 +19,17 @@
#define ROAMING_H #define ROAMING_H
#define DEFAULT_ROAMBUF 65536 #define DEFAULT_ROAMBUF 65536
#define ROAMING_REQUEST "roaming@appgate.com"
extern int roaming_enabled;
extern int resume_in_progress; extern int resume_in_progress;
void request_roaming(void);
int get_snd_buf_size(void); int get_snd_buf_size(void);
int get_recv_buf_size(void); int get_recv_buf_size(void);
void add_recv_bytes(u_int64_t); void add_recv_bytes(u_int64_t);
int wait_for_roaming_reconnect(void);
void roaming_reply(int, u_int32_t, void *);
void set_out_buffer_size(size_t); void set_out_buffer_size(size_t);
ssize_t roaming_write(int, const void *, size_t, int *); ssize_t roaming_write(int, const void *, size_t, int *);
ssize_t roaming_read(int, void *, size_t, int *); ssize_t roaming_read(int, void *, size_t, int *);
@ -33,6 +38,7 @@ u_int64_t get_recv_bytes(void);
u_int64_t get_sent_bytes(void); u_int64_t get_sent_bytes(void);
void roam_set_bytes(u_int64_t, u_int64_t); void roam_set_bytes(u_int64_t, u_int64_t);
void resend_bytes(int, u_int64_t *); void resend_bytes(int, u_int64_t *);
void calculate_new_key(u_int64_t *, u_int64_t, u_int64_t);
int resume_kex(void); int resume_kex(void);
#endif /* ROAMING */ #endif /* ROAMING */

View File

@ -0,0 +1,280 @@
/* $OpenBSD: roaming_client.c,v 1.3 2010/01/18 01:50:27 dtucker Exp $ */
/*
* Copyright (c) 2004-2009 AppGate Network Security AB
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include "openbsd-compat/sys-queue.h"
#include <sys/types.h>
#include <sys/socket.h>
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <openssl/crypto.h>
#include <openssl/sha.h>
#include "xmalloc.h"
#include "buffer.h"
#include "channels.h"
#include "cipher.h"
#include "dispatch.h"
#include "clientloop.h"
#include "log.h"
#include "match.h"
#include "misc.h"
#include "packet.h"
#include "ssh.h"
#include "key.h"
#include "kex.h"
#include "readconf.h"
#include "roaming.h"
#include "ssh2.h"
#include "sshconnect.h"
/* import */
extern Options options;
extern char *host;
extern struct sockaddr_storage hostaddr;
extern int session_resumed;
static u_int32_t roaming_id;
static u_int64_t cookie;
static u_int64_t lastseenchall;
static u_int64_t key1, key2, oldkey1, oldkey2;
void
roaming_reply(int type, u_int32_t seq, void *ctxt)
{
if (type == SSH2_MSG_REQUEST_FAILURE) {
logit("Server denied roaming");
return;
}
verbose("Roaming enabled");
roaming_id = packet_get_int();
cookie = packet_get_int64();
key1 = oldkey1 = packet_get_int64();
key2 = oldkey2 = packet_get_int64();
set_out_buffer_size(packet_get_int() + get_snd_buf_size());
roaming_enabled = 1;
}
void
request_roaming(void)
{
packet_start(SSH2_MSG_GLOBAL_REQUEST);
packet_put_cstring(ROAMING_REQUEST);
packet_put_char(1);
packet_put_int(get_recv_buf_size());
packet_send();
client_register_global_confirm(roaming_reply, NULL);
}
static void
roaming_auth_required(void)
{
u_char digest[SHA_DIGEST_LENGTH];
EVP_MD_CTX md;
Buffer b;
const EVP_MD *evp_md = EVP_sha1();
u_int64_t chall, oldchall;
chall = packet_get_int64();
oldchall = packet_get_int64();
if (oldchall != lastseenchall) {
key1 = oldkey1;
key2 = oldkey2;
}
lastseenchall = chall;
buffer_init(&b);
buffer_put_int64(&b, cookie);
buffer_put_int64(&b, chall);
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&md, digest, NULL);
buffer_free(&b);
packet_start(SSH2_MSG_KEX_ROAMING_AUTH);
packet_put_int64(key1 ^ get_recv_bytes());
packet_put_raw(digest, sizeof(digest));
packet_send();
oldkey1 = key1;
oldkey2 = key2;
calculate_new_key(&key1, cookie, chall);
calculate_new_key(&key2, cookie, chall);
debug("Received %llu bytes", (unsigned long long)get_recv_bytes());
debug("Sent roaming_auth packet");
}
int
resume_kex(void)
{
/*
* This should not happen - if the client sends the kex method
* resume@appgate.com then the kex is done in roaming_resume().
*/
return 1;
}
static int
roaming_resume(void)
{
u_int64_t recv_bytes;
char *str = NULL, *kexlist = NULL, *c;
int i, type;
int timeout_ms = options.connection_timeout * 1000;
u_int len;
u_int32_t rnd = 0;
resume_in_progress = 1;
/* Exchange banners */
ssh_exchange_identification(timeout_ms);
packet_set_nonblocking();
/* Send a kexinit message with resume@appgate.com as only kex algo */
packet_start(SSH2_MSG_KEXINIT);
for (i = 0; i < KEX_COOKIE_LEN; i++) {
if (i % 4 == 0)
rnd = arc4random();
packet_put_char(rnd & 0xff);
rnd >>= 8;
}
packet_put_cstring(KEX_RESUME);
for (i = 1; i < PROPOSAL_MAX; i++) {
/* kex algorithm added so start with i=1 and not 0 */
packet_put_cstring(""); /* Not used when we resume */
}
packet_put_char(1); /* first kex_packet follows */
packet_put_int(0); /* reserved */
packet_send();
/* Assume that resume@appgate.com will be accepted */
packet_start(SSH2_MSG_KEX_ROAMING_RESUME);
packet_put_int(roaming_id);
packet_send();
/* Read the server's kexinit and check for resume@appgate.com */
if ((type = packet_read()) != SSH2_MSG_KEXINIT) {
debug("expected kexinit on resume, got %d", type);
goto fail;
}
for (i = 0; i < KEX_COOKIE_LEN; i++)
(void)packet_get_char();
kexlist = packet_get_string(&len);
if (!kexlist
|| (str = match_list(KEX_RESUME, kexlist, NULL)) == NULL) {
debug("server doesn't allow resume");
goto fail;
}
xfree(str);
for (i = 1; i < PROPOSAL_MAX; i++) {
/* kex algorithm taken care of so start with i=1 and not 0 */
xfree(packet_get_string(&len));
}
i = packet_get_char(); /* first_kex_packet_follows */
if (i && (c = strchr(kexlist, ',')))
*c = 0;
if (i && strcmp(kexlist, KEX_RESUME)) {
debug("server's kex guess (%s) was wrong, skipping", kexlist);
(void)packet_read(); /* Wrong guess - discard packet */
}
/*
* Read the ROAMING_AUTH_REQUIRED challenge from the server and
* send ROAMING_AUTH
*/
if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED) {
debug("expected roaming_auth_required, got %d", type);
goto fail;
}
roaming_auth_required();
/* Read ROAMING_AUTH_OK from the server */
if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_OK) {
debug("expected roaming_auth_ok, got %d", type);
goto fail;
}
recv_bytes = packet_get_int64() ^ oldkey2;
debug("Peer received %llu bytes", (unsigned long long)recv_bytes);
resend_bytes(packet_get_connection_out(), &recv_bytes);
resume_in_progress = 0;
session_resumed = 1; /* Tell clientloop */
return 0;
fail:
if (kexlist)
xfree(kexlist);
if (packet_get_connection_in() == packet_get_connection_out())
close(packet_get_connection_in());
else {
close(packet_get_connection_in());
close(packet_get_connection_out());
}
return 1;
}
int
wait_for_roaming_reconnect(void)
{
static int reenter_guard = 0;
int timeout_ms = options.connection_timeout * 1000;
int c;
if (reenter_guard != 0)
fatal("Server refused resume, roaming timeout may be exceeded");
reenter_guard = 1;
fprintf(stderr, "[connection suspended, press return to resume]");
fflush(stderr);
packet_backup_state();
/* TODO Perhaps we should read from tty here */
while ((c = fgetc(stdin)) != EOF) {
if (c == 'Z' - 64) {
kill(getpid(), SIGTSTP);
continue;
}
if (c != '\n' && c != '\r')
continue;
if (ssh_connect(host, &hostaddr, options.port,
options.address_family, 1, &timeout_ms,
options.tcp_keep_alive, options.use_privileged_port,
options.proxy_command) == 0 && roaming_resume() == 0) {
packet_restore_state();
reenter_guard = 0;
fprintf(stderr, "[connection resumed]\n");
fflush(stderr);
return 0;
}
fprintf(stderr, "[reconnect failed, press return to retry]");
fflush(stderr);
}
fprintf(stderr, "[exiting]\n");
fflush(stderr);
exit(0);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: roaming_common.c,v 1.5 2009/06/27 09:32:43 andreas Exp $ */ /* $OpenBSD: roaming_common.c,v 1.8 2010/01/12 00:59:29 djm Exp $ */
/* /*
* Copyright (c) 2004-2009 AppGate Network Security AB * Copyright (c) 2004-2009 AppGate Network Security AB
* *
@ -52,9 +52,9 @@ int
get_snd_buf_size() get_snd_buf_size()
{ {
int fd = packet_get_connection_out(); int fd = packet_get_connection_out();
int optval, optvallen; int optval;
socklen_t optvallen = sizeof(optval);
optvallen = sizeof(optval);
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optvallen) != 0) if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optvallen) != 0)
optval = DEFAULT_ROAMBUF; optval = DEFAULT_ROAMBUF;
return optval; return optval;
@ -64,9 +64,9 @@ int
get_recv_buf_size() get_recv_buf_size()
{ {
int fd = packet_get_connection_in(); int fd = packet_get_connection_in();
int optval, optvallen; int optval;
socklen_t optvallen = sizeof(optval);
optvallen = sizeof(optval);
if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, &optvallen) != 0) if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, &optvallen) != 0)
optval = DEFAULT_ROAMBUF; optval = DEFAULT_ROAMBUF;
return optval; return optval;
@ -145,8 +145,16 @@ roaming_write(int fd, const void *buf, size_t count, int *cont)
if (out_buf_size > 0) if (out_buf_size > 0)
buf_append(buf, ret); buf_append(buf, ret);
} }
debug3("Wrote %ld bytes for a total of %llu", (long)ret, if (out_buf_size > 0 &&
(unsigned long long)write_bytes); (ret == 0 || (ret == -1 && errno == EPIPE))) {
if (wait_for_roaming_reconnect() != 0) {
ret = 0;
*cont = 1;
} else {
ret = -1;
errno = EAGAIN;
}
}
return ret; return ret;
} }
@ -158,6 +166,15 @@ roaming_read(int fd, void *buf, size_t count, int *cont)
if (!resume_in_progress) { if (!resume_in_progress) {
read_bytes += ret; read_bytes += ret;
} }
} else if (out_buf_size > 0 &&
(ret == 0 || (ret == -1 && (errno == ECONNRESET
|| errno == ECONNABORTED || errno == ETIMEDOUT
|| errno == EHOSTUNREACH)))) {
debug("roaming_read failed for %d ret=%ld errno=%d",
fd, (long)ret, errno);
ret = 0;
if (wait_for_roaming_reconnect() == 0)
*cont = 1;
} }
return ret; return ret;
} }
@ -199,3 +216,29 @@ resend_bytes(int fd, u_int64_t *offset)
atomicio(vwrite, fd, out_buf + (out_last - needed), needed); atomicio(vwrite, fd, out_buf + (out_last - needed), needed);
} }
} }
/*
* Caclulate a new key after a reconnect
*/
void
calculate_new_key(u_int64_t *key, u_int64_t cookie, u_int64_t challenge)
{
const EVP_MD *md = EVP_sha1();
EVP_MD_CTX ctx;
char hash[EVP_MAX_MD_SIZE];
Buffer b;
buffer_init(&b);
buffer_put_int64(&b, *key);
buffer_put_int64(&b, cookie);
buffer_put_int64(&b, challenge);
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, buffer_ptr(&b), buffer_len(&b));
EVP_DigestFinal(&ctx, hash, NULL);
buffer_clear(&b);
buffer_append(&b, hash, EVP_MD_size(md));
*key = buffer_get_int64(&b);
buffer_free(&b);
}

View File

@ -0,0 +1,31 @@
/* $OpenBSD: roaming_serv.c,v 1.1 2009/10/24 11:18:23 andreas Exp $ */
/*
* Copyright (c) 2004-2009 AppGate Network Security AB
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <sys/types.h>
#include "roaming.h"
/*
* Wait for the roaming client to reconnect. Returns 0 if a connect ocurred.
*/
int
wait_for_roaming_reconnect(void)
{
return 1;
}

View File

@ -1,532 +0,0 @@
/*
* Copyright (c) 2002 Juha Yrjölä. All rights reserved.
* Copyright (c) 2001 Markus Friedl.
*
* 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_OPENSC)
#include <sys/types.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <stdarg.h>
#include <string.h>
#include <opensc/opensc.h>
#include <opensc/pkcs15.h>
#include "key.h"
#include "log.h"
#include "xmalloc.h"
#include "misc.h"
#include "scard.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
#define USE_ENGINE
#define RSA_get_default_method RSA_get_default_openssl_method
#else
#endif
#ifdef USE_ENGINE
#include <openssl/engine.h>
#define sc_get_rsa sc_get_engine
#else
#define sc_get_rsa sc_get_rsa_method
#endif
static int sc_reader_id;
static sc_context_t *ctx = NULL;
static sc_card_t *card = NULL;
static sc_pkcs15_card_t *p15card = NULL;
static char *sc_pin = NULL;
struct sc_priv_data
{
struct sc_pkcs15_id cert_id;
int ref_count;
};
void
sc_close(void)
{
if (p15card) {
sc_pkcs15_unbind(p15card);
p15card = NULL;
}
if (card) {
sc_disconnect_card(card, 0);
card = NULL;
}
if (ctx) {
sc_release_context(ctx);
ctx = NULL;
}
}
static int
sc_init(void)
{
int r;
r = sc_establish_context(&ctx, "openssh");
if (r)
goto err;
if (sc_reader_id >= ctx->reader_count) {
r = SC_ERROR_NO_READERS_FOUND;
error("Illegal reader number %d (max %d)", sc_reader_id,
ctx->reader_count -1);
goto err;
}
r = sc_connect_card(ctx->reader[sc_reader_id], 0, &card);
if (r)
goto err;
r = sc_pkcs15_bind(card, &p15card);
if (r)
goto err;
return 0;
err:
sc_close();
return r;
}
/* private key operations */
static int
sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out,
unsigned int usage)
{
int r;
struct sc_priv_data *priv;
struct sc_pkcs15_object *key_obj;
struct sc_pkcs15_prkey_info *key;
struct sc_pkcs15_object *pin_obj;
struct sc_pkcs15_pin_info *pin;
priv = (struct sc_priv_data *) RSA_get_app_data(rsa);
if (priv == NULL)
return -1;
if (p15card == NULL) {
sc_close();
r = sc_init();
if (r) {
error("SmartCard init failed: %s", sc_strerror(r));
goto err;
}
}
r = sc_pkcs15_find_prkey_by_id_usage(p15card, &priv->cert_id,
usage, &key_obj);
if (r) {
error("Unable to find private key from SmartCard: %s",
sc_strerror(r));
goto err;
}
key = key_obj->data;
r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id,
&pin_obj);
if (r == SC_ERROR_OBJECT_NOT_FOUND) {
/* no pin required */
r = sc_lock(card);
if (r) {
error("Unable to lock smartcard: %s", sc_strerror(r));
goto err;
}
*key_obj_out = key_obj;
return 0;
} else if (r) {
error("Unable to find PIN object from SmartCard: %s",
sc_strerror(r));
goto err;
}
pin = pin_obj->data;
r = sc_lock(card);
if (r) {
error("Unable to lock smartcard: %s", sc_strerror(r));
goto err;
}
if (sc_pin != NULL) {
r = sc_pkcs15_verify_pin(p15card, pin, sc_pin,
strlen(sc_pin));
if (r) {
sc_unlock(card);
error("PIN code verification failed: %s",
sc_strerror(r));
goto err;
}
}
*key_obj_out = key_obj;
return 0;
err:
sc_close();
return -1;
}
#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \
SC_PKCS15_PRKEY_USAGE_UNWRAP
static int
sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
struct sc_pkcs15_object *key_obj;
int r;
if (padding != RSA_PKCS1_PADDING)
return -1;
r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_DECRYPT);
if (r)
return -1;
r = sc_pkcs15_decipher(p15card, key_obj, SC_ALGORITHM_RSA_PAD_PKCS1,
from, flen, to, flen);
sc_unlock(card);
if (r < 0) {
error("sc_pkcs15_decipher() failed: %s", sc_strerror(r));
goto err;
}
return r;
err:
sc_close();
return -1;
}
#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
static int
sc_sign(int type, u_char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa)
{
struct sc_pkcs15_object *key_obj;
int r;
unsigned long flags = 0;
/* XXX: sc_prkey_op_init will search for a pkcs15 private
* key object with the sign or signrecover usage flag set.
* If the signing key has only the non-repudiation flag set
* the key will be rejected as using a non-repudiation key
* for authentication is not recommended. Note: This does not
* prevent the use of a non-repudiation key for authentication
* if the sign or signrecover flag is set as well.
*/
r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_SIGN);
if (r)
return -1;
/* FIXME: length of sigret correct? */
/* FIXME: check 'type' and modify flags accordingly */
flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1;
r = sc_pkcs15_compute_signature(p15card, key_obj, flags,
m, m_len, sigret, RSA_size(rsa));
sc_unlock(card);
if (r < 0) {
error("sc_pkcs15_compute_signature() failed: %s",
sc_strerror(r));
goto err;
}
*siglen = r;
return 1;
err:
sc_close();
return 0;
}
static int
sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
int padding)
{
error("Private key encryption not supported");
return -1;
}
/* called on free */
static int (*orig_finish)(RSA *rsa) = NULL;
static int
sc_finish(RSA *rsa)
{
struct sc_priv_data *priv;
priv = RSA_get_app_data(rsa);
priv->ref_count--;
if (priv->ref_count == 0) {
free(priv);
sc_close();
}
if (orig_finish)
orig_finish(rsa);
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 = "opensc";
/* overload */
smart_rsa.rsa_priv_enc = sc_private_encrypt;
smart_rsa.rsa_priv_dec = sc_private_decrypt;
smart_rsa.rsa_sign = sc_sign;
/* 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, "opensc");
ENGINE_set_name(smart_engine, "OpenSC");
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
static void
convert_rsa_to_rsa1(Key * in, Key * out)
{
struct sc_priv_data *priv;
out->rsa->flags = in->rsa->flags;
out->flags = in->flags;
RSA_set_method(out->rsa, RSA_get_method(in->rsa));
BN_copy(out->rsa->n, in->rsa->n);
BN_copy(out->rsa->e, in->rsa->e);
priv = RSA_get_app_data(in->rsa);
priv->ref_count++;
RSA_set_app_data(out->rsa, priv);
return;
}
static int
sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj)
{
int r;
sc_pkcs15_cert_t *cert = NULL;
struct sc_priv_data *priv = NULL;
sc_pkcs15_cert_info_t *cinfo = cert_obj->data;
X509 *x509 = NULL;
EVP_PKEY *pubkey = NULL;
u8 *p;
char *tmp;
debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]);
r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
if (r) {
logit("Certificate read failed: %s", sc_strerror(r));
goto err;
}
x509 = X509_new();
if (x509 == NULL) {
r = -1;
goto err;
}
p = cert->data;
if (!d2i_X509(&x509, &p, cert->data_len)) {
logit("Unable to parse X.509 certificate");
r = -1;
goto err;
}
sc_pkcs15_free_certificate(cert);
cert = NULL;
pubkey = X509_get_pubkey(x509);
X509_free(x509);
x509 = NULL;
if (pubkey->type != EVP_PKEY_RSA) {
logit("Public key is of unknown type");
r = -1;
goto err;
}
k->rsa = EVP_PKEY_get1_RSA(pubkey);
EVP_PKEY_free(pubkey);
k->rsa->flags |= RSA_FLAG_SIGN_VER;
RSA_set_method(k->rsa, sc_get_rsa_method());
priv = xmalloc(sizeof(struct sc_priv_data));
priv->cert_id = cinfo->id;
priv->ref_count = 1;
RSA_set_app_data(k->rsa, priv);
k->flags = KEY_FLAG_EXT;
tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
debug("fingerprint %d %s", key_size(k), tmp);
xfree(tmp);
return 0;
err:
if (cert)
sc_pkcs15_free_certificate(cert);
if (pubkey)
EVP_PKEY_free(pubkey);
if (x509)
X509_free(x509);
return r;
}
Key **
sc_get_keys(const char *id, const char *pin)
{
Key *k, **keys;
int i, r, real_count = 0, key_count;
sc_pkcs15_id_t cert_id;
sc_pkcs15_object_t *certs[32];
char *buf = xstrdup(id), *p;
debug("sc_get_keys called: id = %s", id);
if (sc_pin != NULL)
xfree(sc_pin);
sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
cert_id.len = 0;
if ((p = strchr(buf, ':')) != NULL) {
*p = 0;
p++;
sc_pkcs15_hex_string_to_id(p, &cert_id);
}
r = sscanf(buf, "%d", &sc_reader_id);
xfree(buf);
if (r != 1)
goto err;
if (p15card == NULL) {
sc_close();
r = sc_init();
if (r) {
error("Smartcard init failed: %s", sc_strerror(r));
goto err;
}
}
if (cert_id.len) {
r = sc_pkcs15_find_cert_by_id(p15card, &cert_id, &certs[0]);
if (r < 0)
goto err;
key_count = 1;
} else {
r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509,
certs, 32);
if (r == 0) {
logit("No certificates found on smartcard");
r = -1;
goto err;
} else if (r < 0) {
error("Certificate enumeration failed: %s",
sc_strerror(r));
goto err;
}
key_count = r;
}
if (key_count > 1024)
fatal("Too many keys (%u), expected <= 1024", key_count);
keys = xcalloc(key_count * 2 + 1, sizeof(Key *));
for (i = 0; i < key_count; i++) {
sc_pkcs15_object_t *tmp_obj = NULL;
cert_id = ((sc_pkcs15_cert_info_t *)(certs[i]->data))->id;
if (sc_pkcs15_find_prkey_by_id(p15card, &cert_id, &tmp_obj))
/* skip the public key (certificate) if no
* corresponding private key is present */
continue;
k = key_new(KEY_RSA);
if (k == NULL)
break;
r = sc_read_pubkey(k, certs[i]);
if (r) {
error("sc_read_pubkey failed: %s", sc_strerror(r));
key_free(k);
continue;
}
keys[real_count] = k;
real_count++;
k = key_new(KEY_RSA1);
if (k == NULL)
break;
convert_rsa_to_rsa1(keys[real_count-1], k);
keys[real_count] = k;
real_count++;
}
keys[real_count] = NULL;
return keys;
err:
sc_close();
return NULL;
}
int
sc_put_key(Key *prv, const char *id)
{
error("key uploading not yet supported");
return -1;
}
char *
sc_get_key_label(Key *key)
{
int r;
const struct sc_priv_data *priv;
struct sc_pkcs15_object *key_obj;
priv = (const struct sc_priv_data *) RSA_get_app_data(key->rsa);
if (priv == NULL || p15card == NULL) {
logit("SmartCard key not loaded");
/* internal error => return default label */
return xstrdup("smartcard key");
}
r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj);
if (r) {
logit("Unable to find private key from SmartCard: %s",
sc_strerror(r));
return xstrdup("smartcard key");
}
if (key_obj == NULL || key_obj->label == NULL)
/* the optional PKCS#15 label does not exists
* => return the default label */
return xstrdup("smartcard key");
return xstrdup(key_obj->label);
}
#endif /* SMARTCARD */

View File

@ -1,571 +0,0 @@
/* $OpenBSD: scard.c,v 1.36 2006/11/06 21:25:28 markus Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#if defined(SMARTCARD) && defined(USE_SECTOK)
#include <sys/types.h>
#include <sectok.h>
#include <stdarg.h>
#include <string.h>
#include <openssl/evp.h>
#include "xmalloc.h"
#include "key.h"
#include "log.h"
#include "misc.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 <openssl/engine.h>
#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 %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 = xcalloc((nkeys+1), sizeof(Key *));
n = key_new(KEY_RSA1);
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
fatal("sc_get_keys: BN_copy failed");
RSA_set_method(n->rsa, sc_get_rsa());
n->flags |= KEY_FLAG_EXT;
keys[0] = n;
n = key_new(KEY_RSA);
if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
(BN_copy(n->rsa->e, k->rsa->e) == NULL))
fatal("sc_get_keys: BN_copy failed");
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;
logit("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;
logit("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);
}
char *
sc_get_key_label(Key *key)
{
return xstrdup("smartcard key");
}
#endif /* SMARTCARD && USE_SECTOK */

View File

@ -1,39 +0,0 @@
/* $OpenBSD: scard.h,v 1.14 2006/08/03 03:34:42 deraadt Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SCARD_H
#define SCARD_H
#define SCARD_ERROR_FAIL -1
#define SCARD_ERROR_NOCARD -2
#define SCARD_ERROR_APPLET -3
Key **sc_get_keys(const char *, const char *);
void sc_close(void);
int sc_put_key(Key *, const char *);
char *sc_get_key_label(Key *);
#endif

View File

@ -9,9 +9,9 @@
.\" .\"
.\" Created: Sun May 7 00:14:37 1995 ylo .\" Created: Sun May 7 00:14:37 1995 ylo
.\" .\"
.\" $OpenBSD: scp.1,v 1.46 2008/07/12 05:33:41 djm Exp $ .\" $OpenBSD: scp.1,v 1.50 2010/02/08 10:50:20 markus Exp $
.\" .\"
.Dd July 12 2008 .Dd February 8 2010
.Dt SCP 1 .Dt SCP 1
.Os .Os
.Sh NAME .Sh NAME
@ -153,6 +153,7 @@ For full details of the options listed below, and their possible values, see
.It NoHostAuthenticationForLocalhost .It NoHostAuthenticationForLocalhost
.It NumberOfPasswordPrompts .It NumberOfPasswordPrompts
.It PasswordAuthentication .It PasswordAuthentication
.It PKCS11Provider
.It Port .It Port
.It PreferredAuthentications .It PreferredAuthentications
.It Protocol .It Protocol
@ -164,7 +165,6 @@ For full details of the options listed below, and their possible values, see
.It SendEnv .It SendEnv
.It ServerAliveInterval .It ServerAliveInterval
.It ServerAliveCountMax .It ServerAliveCountMax
.It SmartcardDevice
.It StrictHostKeyChecking .It StrictHostKeyChecking
.It TCPKeepAlive .It TCPKeepAlive
.It UsePrivilegedPort .It UsePrivilegedPort

View File

@ -1,4 +1,4 @@
/* $OpenBSD: scp.c,v 1.164 2008/10/10 04:55:16 stevesk Exp $ */ /* $OpenBSD: scp.c,v 1.165 2009/12/20 07:28:36 guenther Exp $ */
/* /*
* scp - secure remote copy. This is basically patched BSD rcp which * scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd). * uses ssh to do the data transfer (instead of using rcmd).
@ -244,8 +244,11 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
close(pout[1]); close(pout[1]);
replacearg(&args, 0, "%s", ssh_program); replacearg(&args, 0, "%s", ssh_program);
if (remuser != NULL) if (remuser != NULL) {
addargs(&args, "-l%s", remuser); addargs(&args, "-l");
addargs(&args, "%s", remuser);
}
addargs(&args, "--");
addargs(&args, "%s", host); addargs(&args, "%s", host);
addargs(&args, "%s", cmd); addargs(&args, "%s", cmd);
@ -337,10 +340,12 @@ main(int argc, char **argv)
case 'c': case 'c':
case 'i': case 'i':
case 'F': case 'F':
addargs(&args, "-%c%s", ch, optarg); addargs(&args, "-%c", ch);
addargs(&args, "%s", optarg);
break; break;
case 'P': case 'P':
addargs(&args, "-p%s", optarg); addargs(&args, "-p");
addargs(&args, "%s", optarg);
break; break;
case 'B': case 'B':
addargs(&args, "-oBatchmode yes"); addargs(&args, "-oBatchmode yes");
@ -548,6 +553,7 @@ toremote(char *targ, int argc, char **argv)
} else { } else {
host = cleanhostname(argv[i]); host = cleanhostname(argv[i]);
} }
addargs(&alist, "--");
addargs(&alist, "%s", host); addargs(&alist, "%s", host);
addargs(&alist, "%s", cmd); addargs(&alist, "%s", cmd);
addargs(&alist, "%s", src); addargs(&alist, "%s", src);
@ -558,7 +564,7 @@ toremote(char *targ, int argc, char **argv)
errs = 1; errs = 1;
} else { /* local to remote */ } else { /* local to remote */
if (remin == -1) { if (remin == -1) {
xasprintf(&bp, "%s -t %s", cmd, targ); xasprintf(&bp, "%s -t -- %s", cmd, targ);
host = cleanhostname(thost); host = cleanhostname(thost);
if (do_cmd(host, tuser, bp, &remin, if (do_cmd(host, tuser, bp, &remin,
&remout) < 0) &remout) < 0)
@ -591,6 +597,7 @@ tolocal(int argc, char **argv)
addargs(&alist, "-r"); addargs(&alist, "-r");
if (pflag) if (pflag)
addargs(&alist, "-p"); addargs(&alist, "-p");
addargs(&alist, "--");
addargs(&alist, "%s", argv[i]); addargs(&alist, "%s", argv[i]);
addargs(&alist, "%s", argv[argc-1]); addargs(&alist, "%s", argv[argc-1]);
if (do_local_cmd(&alist)) if (do_local_cmd(&alist))
@ -610,7 +617,7 @@ tolocal(int argc, char **argv)
suser = pwd->pw_name; suser = pwd->pw_name;
} }
host = cleanhostname(host); host = cleanhostname(host);
xasprintf(&bp, "%s -f %s", cmd, src); xasprintf(&bp, "%s -f -- %s", cmd, src);
if (do_cmd(host, suser, bp, &remin, &remout) < 0) { if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
(void) xfree(bp); (void) xfree(bp);
++errs; ++errs;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.c,v 1.195 2009/04/14 21:10:54 jj Exp $ */ /* $OpenBSD: servconf.c,v 1.204 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -42,6 +42,7 @@ __RCSID("$FreeBSD$");
#include "match.h" #include "match.h"
#include "channels.h" #include "channels.h"
#include "groupaccess.h" #include "groupaccess.h"
#include "version.h"
static void add_listen_addr(ServerOptions *, char *, int); static void add_listen_addr(ServerOptions *, char *, int);
static void add_one_listen_addr(ServerOptions *, char *, int); static void add_one_listen_addr(ServerOptions *, char *, int);
@ -66,6 +67,7 @@ initialize_server_options(ServerOptions *options)
options->listen_addrs = NULL; options->listen_addrs = NULL;
options->address_family = -1; options->address_family = -1;
options->num_host_key_files = 0; options->num_host_key_files = 0;
options->num_host_cert_files = 0;
options->pid_file = NULL; options->pid_file = NULL;
options->server_key_bits = -1; options->server_key_bits = -1;
options->login_grace_time = -1; options->login_grace_time = -1;
@ -129,6 +131,8 @@ initialize_server_options(ServerOptions *options)
options->adm_forced_command = NULL; options->adm_forced_command = NULL;
options->chroot_directory = NULL; options->chroot_directory = NULL;
options->zero_knowledge_password_authentication = -1; options->zero_knowledge_password_authentication = -1;
options->revoked_keys_file = NULL;
options->trusted_user_ca_keys = NULL;
} }
void void
@ -153,6 +157,7 @@ fill_default_server_options(ServerOptions *options)
_PATH_HOST_DSA_KEY_FILE; _PATH_HOST_DSA_KEY_FILE;
} }
} }
/* No certificates by default */
if (options->num_ports == 0) if (options->num_ports == 0)
options->ports[options->num_ports++] = SSH_DEFAULT_PORT; options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
if (options->listen_addrs == NULL) if (options->listen_addrs == NULL)
@ -306,7 +311,8 @@ typedef enum {
sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
sUsePrivilegeSeparation, sAllowAgentForwarding, sUsePrivilegeSeparation, sAllowAgentForwarding,
sZeroKnowledgePasswordAuthentication, sZeroKnowledgePasswordAuthentication, sHostCertificate,
sRevokedKeys, sTrustedUserCAKeys,
sVersionAddendum, sVersionAddendum,
sDeprecated, sUnsupported sDeprecated, sUnsupported
} ServerOpCodes; } ServerOpCodes;
@ -426,6 +432,9 @@ static struct {
{ "permitopen", sPermitOpen, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL },
{ "forcecommand", sForceCommand, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL },
{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
{ NULL, sBadOption, 0 } { NULL, sBadOption, 0 }
}; };
@ -462,6 +471,22 @@ parse_token(const char *cp, const char *filename,
return sBadOption; return sBadOption;
} }
char *
derelativise_path(const char *path)
{
char *expanded, *ret, *cwd;
expanded = tilde_expand_filename(path, getuid());
if (*expanded == '/')
return expanded;
if ((cwd = getcwd(NULL, 0)) == NULL)
fatal("%s: getcwd: %s", __func__, strerror(errno));
xasprintf(&ret, "%s/%s", cwd, expanded);
xfree(cwd);
xfree(expanded);
return ret;
}
static void static void
add_listen_addr(ServerOptions *options, char *addr, int port) add_listen_addr(ServerOptions *options, char *addr, int port)
{ {
@ -796,13 +821,23 @@ process_server_config_line(ServerOptions *options, char *line,
fatal("%s line %d: missing file name.", fatal("%s line %d: missing file name.",
filename, linenum); filename, linenum);
if (*activep && *charptr == NULL) { if (*activep && *charptr == NULL) {
*charptr = tilde_expand_filename(arg, getuid()); *charptr = derelativise_path(arg);
/* increase optional counter */ /* increase optional counter */
if (intptr != NULL) if (intptr != NULL)
*intptr = *intptr + 1; *intptr = *intptr + 1;
} }
break; break;
case sHostCertificate:
intptr = &options->num_host_cert_files;
if (*intptr >= MAX_HOSTKEYS)
fatal("%s line %d: too many host certificates "
"specified (max %d).", filename, linenum,
MAX_HOSTCERTS);
charptr = &options->host_cert_files[*intptr];
goto parse_filename;
break;
case sPidFile: case sPidFile:
charptr = &options->pid_file; charptr = &options->pid_file;
goto parse_filename; goto parse_filename;
@ -1297,6 +1332,14 @@ process_server_config_line(ServerOptions *options, char *line,
*charptr = xstrdup(arg); *charptr = xstrdup(arg);
break; break;
case sTrustedUserCAKeys:
charptr = &options->trusted_user_ca_keys;
goto parse_filename;
case sRevokedKeys:
charptr = &options->revoked_keys_file;
goto parse_filename;
case sVersionAddendum: case sVersionAddendum:
ssh_version_set_addendum(strtok(cp, "\n")); ssh_version_set_addendum(strtok(cp, "\n"));
do { do {
@ -1418,6 +1461,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
return; return;
M_CP_STROPT(adm_forced_command); M_CP_STROPT(adm_forced_command);
M_CP_STROPT(chroot_directory); M_CP_STROPT(chroot_directory);
M_CP_STROPT(trusted_user_ca_keys);
M_CP_STROPT(revoked_keys_file);
} }
#undef M_CP_INTOPT #undef M_CP_INTOPT
@ -1636,6 +1681,9 @@ dump_config(ServerOptions *o)
dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file); dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
dump_cfg_string(sForceCommand, o->adm_forced_command); dump_cfg_string(sForceCommand, o->adm_forced_command);
dump_cfg_string(sChrootDirectory, o->chroot_directory);
dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
/* string arguments requiring a lookup */ /* string arguments requiring a lookup */
dump_cfg_string(sLogLevel, log_level_name(o->log_level)); dump_cfg_string(sLogLevel, log_level_name(o->log_level));
@ -1644,6 +1692,8 @@ dump_config(ServerOptions *o)
/* string array arguments */ /* string array arguments */
dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
o->host_key_files); o->host_key_files);
dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files,
o->host_cert_files);
dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users); dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups); dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.87 2009/01/22 10:02:34 djm Exp $ */ /* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -24,6 +24,7 @@
#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
#define MAX_HOSTKEYS 256 /* Max # hostkeys. */ #define MAX_HOSTKEYS 256 /* Max # hostkeys. */
#define MAX_HOSTCERTS 256 /* Max # host certificates. */
#define MAX_ACCEPT_ENV 256 /* Max # of env vars. */ #define MAX_ACCEPT_ENV 256 /* Max # of env vars. */
#define MAX_MATCH_GROUPS 256 /* Max # of groups for Match. */ #define MAX_MATCH_GROUPS 256 /* Max # of groups for Match. */
@ -49,6 +50,8 @@ typedef struct {
int address_family; /* Address family used by the server. */ int address_family; /* Address family used by the server. */
char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */ char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */
int num_host_key_files; /* Number of files for host keys. */ int num_host_key_files; /* Number of files for host keys. */
char *host_cert_files[MAX_HOSTCERTS]; /* Files containing host certs. */
int num_host_cert_files; /* Number of files for host certs. */
char *pid_file; /* Where to put our pid */ char *pid_file; /* Where to put our pid */
int server_key_bits;/* Size of the server key. */ int server_key_bits;/* Size of the server key. */
int login_grace_time; /* Disconnect if no auth in this time int login_grace_time; /* Disconnect if no auth in this time
@ -151,6 +154,8 @@ typedef struct {
int num_permitted_opens; int num_permitted_opens;
char *chroot_directory; char *chroot_directory;
char *revoked_keys_file;
char *trusted_user_ca_keys;
} ServerOptions; } ServerOptions;
void initialize_server_options(ServerOptions *); void initialize_server_options(ServerOptions *);
@ -164,5 +169,6 @@ void parse_server_match_config(ServerOptions *, const char *, const char *,
const char *); const char *);
void copy_set_server_options(ServerOptions *, ServerOptions *, int); void copy_set_server_options(ServerOptions *, ServerOptions *, int);
void dump_config(ServerOptions *); void dump_config(ServerOptions *);
char *derelativise_path(const char *);
#endif /* SERVCONF_H */ #endif /* SERVCONF_H */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.246 2009/04/17 19:23:06 stevesk Exp $ */ /* $OpenBSD: session.c,v 1.252 2010/03/07 11:57:13 dtucker Exp $ */
/* /*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved * All rights reserved
@ -143,9 +143,10 @@ static int sessions_first_unused = -1;
static int sessions_nalloc = 0; static int sessions_nalloc = 0;
static Session *sessions = NULL; static Session *sessions = NULL;
#define SUBSYSTEM_NONE 0 #define SUBSYSTEM_NONE 0
#define SUBSYSTEM_EXT 1 #define SUBSYSTEM_EXT 1
#define SUBSYSTEM_INT_SFTP 2 #define SUBSYSTEM_INT_SFTP 2
#define SUBSYSTEM_INT_SFTP_ERROR 3
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
login_cap_t *lc; login_cap_t *lc;
@ -271,6 +272,8 @@ do_authenticated(Authctxt *authctxt)
if (!no_port_forwarding_flag && options.allow_tcp_forwarding) if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
channel_permit_all_opens(); channel_permit_all_opens();
auth_debug_send();
if (compat20) if (compat20)
do_authenticated2(authctxt); do_authenticated2(authctxt);
else else
@ -786,17 +789,19 @@ do_exec(Session *s, const char *command)
if (options.adm_forced_command) { if (options.adm_forced_command) {
original_command = command; original_command = command;
command = options.adm_forced_command; command = options.adm_forced_command;
if (IS_INTERNAL_SFTP(command)) if (IS_INTERNAL_SFTP(command)) {
s->is_subsystem = SUBSYSTEM_INT_SFTP; s->is_subsystem = s->is_subsystem ?
else if (s->is_subsystem) SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
} else if (s->is_subsystem)
s->is_subsystem = SUBSYSTEM_EXT; s->is_subsystem = SUBSYSTEM_EXT;
debug("Forced command (config) '%.900s'", command); debug("Forced command (config) '%.900s'", command);
} else if (forced_command) { } else if (forced_command) {
original_command = command; original_command = command;
command = forced_command; command = forced_command;
if (IS_INTERNAL_SFTP(command)) if (IS_INTERNAL_SFTP(command)) {
s->is_subsystem = SUBSYSTEM_INT_SFTP; s->is_subsystem = s->is_subsystem ?
else if (s->is_subsystem) SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
} else if (s->is_subsystem)
s->is_subsystem = SUBSYSTEM_EXT; s->is_subsystem = SUBSYSTEM_EXT;
debug("Forced command (key option) '%.900s'", command); debug("Forced command (key option) '%.900s'", command);
} }
@ -1404,26 +1409,32 @@ static void
do_nologin(struct passwd *pw) do_nologin(struct passwd *pw)
{ {
FILE *f = NULL; FILE *f = NULL;
char buf[1024]; char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
struct stat sb;
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, return;
_PATH_NOLOGIN), "r"); nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
#else #else
if (pw->pw_uid) if (pw->pw_uid == 0)
f = fopen(_PATH_NOLOGIN, "r"); return;
nl = def_nl;
#endif #endif
if (f) { if (stat(nl, &sb) == -1) {
/* /etc/nologin exists. Print its contents and exit. */ if (nl != def_nl)
logit("User %.100s not allowed because %s exists", xfree(nl);
pw->pw_name, _PATH_NOLOGIN); return;
while (fgets(buf, sizeof(buf), f))
fputs(buf, stderr);
fclose(f);
fflush(NULL);
exit(254);
} }
/* /etc/nologin exists. Print its contents if we can and exit. */
logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
if ((f = fopen(nl, "r")) != NULL) {
while (fgets(buf, sizeof(buf), f))
fputs(buf, stderr);
fclose(f);
}
exit(254);
} }
/* /*
@ -1551,6 +1562,24 @@ do_setusercontext(struct passwd *pw)
} }
# endif /* USE_LIBIAF */ # endif /* USE_LIBIAF */
#endif #endif
#ifdef HAVE_SETPCRED
/*
* If we have a chroot directory, we set all creds except real
* uid which we will need for chroot. If we don't have a
* chroot directory, we don't override anything.
*/
{
char **creds = NULL, *chroot_creds[] =
{ "REAL_USER=root", NULL };
if (options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0)
creds = chroot_creds;
if (setpcred(pw->pw_name, creds) == -1)
fatal("Failed to set process credentials");
}
#endif /* HAVE_SETPCRED */
if (options.chroot_directory != NULL && if (options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0) { strcasecmp(options.chroot_directory, "none") != 0) {
@ -1563,10 +1592,6 @@ do_setusercontext(struct passwd *pw)
free(chroot_path); free(chroot_path);
} }
#ifdef HAVE_SETPCRED
if (setpcred(pw->pw_name, (char **)NULL) == -1)
fatal("Failed to set process credentials");
#endif /* HAVE_SETPCRED */
#ifdef HAVE_LOGIN_CAP #ifdef HAVE_LOGIN_CAP
if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
perror("unable to set user context (setuser)"); perror("unable to set user context (setuser)");
@ -1813,7 +1838,11 @@ do_child(Session *s, const char *command)
/* restore SIGPIPE for child */ /* restore SIGPIPE for child */
signal(SIGPIPE, SIG_DFL); signal(SIGPIPE, SIG_DFL);
if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
printf("This service allows sftp connections only.\n");
fflush(NULL);
exit(1);
} else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
extern int optind, optreset; extern int optind, optreset;
int i; int i;
char *p, *args; char *p, *args;
@ -1826,9 +1855,14 @@ do_child(Session *s, const char *command)
argv[i] = NULL; argv[i] = NULL;
optind = optreset = 1; optind = optreset = 1;
__progname = argv[0]; __progname = argv[0];
#ifdef WITH_SELINUX
ssh_selinux_change_context("sftpd_t");
#endif
exit(sftp_server_main(i, argv, s->pw)); exit(sftp_server_main(i, argv, s->pw));
} }
fflush(NULL);
if (options.use_login) { if (options.use_login) {
launch_login(pw, hostname); launch_login(pw, hostname);
/* NEVERREACHED */ /* NEVERREACHED */
@ -2139,16 +2173,16 @@ session_subsystem_req(Session *s)
if (strcmp(subsys, options.subsystem_name[i]) == 0) { if (strcmp(subsys, options.subsystem_name[i]) == 0) {
prog = options.subsystem_command[i]; prog = options.subsystem_command[i];
cmd = options.subsystem_args[i]; cmd = options.subsystem_args[i];
if (!strcmp(INTERNAL_SFTP_NAME, prog)) { if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
s->is_subsystem = SUBSYSTEM_INT_SFTP; s->is_subsystem = SUBSYSTEM_INT_SFTP;
} else if (stat(prog, &st) < 0) { debug("subsystem: %s", prog);
error("subsystem: cannot stat %s: %s", prog,
strerror(errno));
break;
} else { } else {
if (stat(prog, &st) < 0)
debug("subsystem: cannot stat %s: %s",
prog, strerror(errno));
s->is_subsystem = SUBSYSTEM_EXT; s->is_subsystem = SUBSYSTEM_EXT;
debug("subsystem: exec() %s", cmd);
} }
debug("subsystem: exec() %s", cmd);
success = do_exec(s, cmd) == 0; success = do_exec(s, cmd) == 0;
break; break;
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.87 2009/06/22 05:39:28 dtucker Exp $ */ /* $OpenBSD: sftp-client.c,v 1.90 2009/10/11 10:41:26 dtucker Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
* *
@ -36,6 +36,7 @@
#endif #endif
#include <sys/uio.h> #include <sys/uio.h>
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
@ -61,6 +62,9 @@ extern int showprogress;
/* Minimum amount of data to read at a time */ /* Minimum amount of data to read at a time */
#define MIN_READ_SIZE 512 #define MIN_READ_SIZE 512
/* Maximum depth to descend in directory trees */
#define MAX_DIR_DEPTH 64
struct sftp_conn { struct sftp_conn {
int fd_in; int fd_in;
int fd_out; int fd_out;
@ -74,6 +78,10 @@ struct sftp_conn {
u_int exts; u_int exts;
}; };
static char *
get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...)
__attribute__((format(printf, 4, 5)));
static void static void
send_msg(int fd, Buffer *m) send_msg(int fd, Buffer *m)
{ {
@ -179,11 +187,18 @@ get_status(int fd, u_int expected_id)
} }
static char * static char *
get_handle(int fd, u_int expected_id, u_int *len) get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...)
{ {
Buffer msg; Buffer msg;
u_int type, id; u_int type, id;
char *handle; char *handle, errmsg[256];
va_list args;
int status;
va_start(args, errfmt);
if (errfmt != NULL)
vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
va_end(args);
buffer_init(&msg); buffer_init(&msg);
get_msg(fd, &msg); get_msg(fd, &msg);
@ -191,16 +206,17 @@ get_handle(int fd, u_int expected_id, u_int *len)
id = buffer_get_int(&msg); id = buffer_get_int(&msg);
if (id != expected_id) if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id); fatal("%s: ID mismatch (%u != %u)",
errfmt == NULL ? __func__ : errmsg, id, expected_id);
if (type == SSH2_FXP_STATUS) { if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg); status = buffer_get_int(&msg);
if (errfmt != NULL)
error("Couldn't get handle: %s", fx2txt(status)); error("%s: %s", errmsg, fx2txt(status));
buffer_free(&msg); buffer_free(&msg);
return(NULL); return(NULL);
} else if (type != SSH2_FXP_HANDLE) } else if (type != SSH2_FXP_HANDLE)
fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
SSH2_FXP_HANDLE, type); errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
handle = buffer_get_string(&msg, len); handle = buffer_get_string(&msg, len);
buffer_free(&msg); buffer_free(&msg);
@ -418,7 +434,8 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
buffer_clear(&msg); buffer_clear(&msg);
handle = get_handle(conn->fd_in, id, &handle_len); handle = get_handle(conn->fd_in, id, &handle_len,
"remote readdir(\"%s\")", path);
if (handle == NULL) if (handle == NULL)
return(-1); return(-1);
@ -484,6 +501,17 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
if (printflag) if (printflag)
printf("%s\n", longname); printf("%s\n", longname);
/*
* Directory entries should never contain '/'
* These can be used to attack recursive ops
* (e.g. send '../../../../etc/passwd')
*/
if (strchr(filename, '/') != NULL) {
error("Server sent suspect path \"%s\" "
"during readdir of \"%s\"", filename, path);
goto next;
}
if (dir) { if (dir) {
*dir = xrealloc(*dir, ents + 2, sizeof(**dir)); *dir = xrealloc(*dir, ents + 2, sizeof(**dir));
(*dir)[ents] = xmalloc(sizeof(***dir)); (*dir)[ents] = xmalloc(sizeof(***dir));
@ -492,7 +520,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
memcpy(&(*dir)[ents]->a, a, sizeof(*a)); memcpy(&(*dir)[ents]->a, a, sizeof(*a));
(*dir)[++ents] = NULL; (*dir)[++ents] = NULL;
} }
next:
xfree(filename); xfree(filename);
xfree(longname); xfree(longname);
} }
@ -547,7 +575,7 @@ do_rm(struct sftp_conn *conn, char *path)
} }
int int
do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag)
{ {
u_int status, id; u_int status, id;
@ -556,7 +584,7 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a)
strlen(path), a); strlen(path), a);
status = get_status(conn->fd_in, id); status = get_status(conn->fd_in, id);
if (status != SSH2_FX_OK) if (status != SSH2_FX_OK && printflag)
error("Couldn't create directory: %s", fx2txt(status)); error("Couldn't create directory: %s", fx2txt(status));
return(status); return(status);
@ -895,9 +923,9 @@ send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
int int
do_download(struct sftp_conn *conn, char *remote_path, char *local_path, do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
int pflag) Attrib *a, int pflag)
{ {
Attrib junk, *a; Attrib junk;
Buffer msg; Buffer msg;
char *handle; char *handle;
int local_fd, status = 0, write_error; int local_fd, status = 0, write_error;
@ -916,9 +944,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
TAILQ_INIT(&requests); TAILQ_INIT(&requests);
a = do_stat(conn, remote_path, 0); if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
if (a == NULL) return -1;
return(-1);
/* Do not preserve set[ug]id here, as we do not preserve ownership */ /* Do not preserve set[ug]id here, as we do not preserve ownership */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
@ -951,7 +978,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
send_msg(conn->fd_out, &msg); send_msg(conn->fd_out, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%u 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); handle = get_handle(conn->fd_in, id, &handle_len,
"remote open(\"%s\")", remote_path);
if (handle == NULL) { if (handle == NULL) {
buffer_free(&msg); buffer_free(&msg);
return(-1); return(-1);
@ -1132,6 +1160,114 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
return(status); return(status);
} }
static int
download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
Attrib *dirattrib, int pflag, int printflag, int depth)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
char *filename, *new_src, *new_dst;
mode_t mode = 0777;
if (depth >= MAX_DIR_DEPTH) {
error("Maximum directory depth exceeded: %d levels", depth);
return -1;
}
if (dirattrib == NULL &&
(dirattrib = do_stat(conn, src, 1)) == NULL) {
error("Unable to stat remote directory \"%s\"", src);
return -1;
}
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" is not a directory", src);
return -1;
}
if (printflag)
printf("Retrieving %s\n", src);
if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
mode = dirattrib->perm & 01777;
else {
debug("Server did not send permissions for "
"directory \"%s\"", dst);
}
if (mkdir(dst, mode) == -1 && errno != EEXIST) {
error("mkdir %s: %s", dst, strerror(errno));
return -1;
}
if (do_readdir(conn, src, &dir_entries) == -1) {
error("%s: Failed to get directory contents", src);
return -1;
}
for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
filename = dir_entries[i]->filename;
new_dst = path_append(dst, filename);
new_src = path_append(src, filename);
if (S_ISDIR(dir_entries[i]->a.perm)) {
if (strcmp(filename, ".") == 0 ||
strcmp(filename, "..") == 0)
continue;
if (download_dir_internal(conn, new_src, new_dst,
&(dir_entries[i]->a), pflag, printflag,
depth + 1) == -1)
ret = -1;
} else if (S_ISREG(dir_entries[i]->a.perm) ) {
if (do_download(conn, new_src, new_dst,
&(dir_entries[i]->a), pflag) == -1) {
error("Download of file %s to %s failed",
new_src, new_dst);
ret = -1;
}
} else
logit("%s: not a regular file\n", new_src);
xfree(new_dst);
xfree(new_src);
}
if (pflag) {
if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
struct timeval tv[2];
tv[0].tv_sec = dirattrib->atime;
tv[1].tv_sec = dirattrib->mtime;
tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(dst, tv) == -1)
error("Can't set times on \"%s\": %s",
dst, strerror(errno));
} else
debug("Server did not send times for directory "
"\"%s\"", dst);
}
free_sftp_dirents(dir_entries);
return ret;
}
int
download_dir(struct sftp_conn *conn, char *src, char *dst,
Attrib *dirattrib, int pflag, int printflag)
{
char *src_canon;
int ret;
if ((src_canon = do_realpath(conn, src)) == NULL) {
error("Unable to canonicalise path \"%s\"", src);
return -1;
}
ret = download_dir_internal(conn, src_canon, dst,
dirattrib, pflag, printflag, 0);
xfree(src_canon);
return ret;
}
int int
do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
int pflag) int pflag)
@ -1195,7 +1331,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
buffer_clear(&msg); buffer_clear(&msg);
handle = get_handle(conn->fd_in, id, &handle_len); handle = get_handle(conn->fd_in, id, &handle_len,
"remote open(\"%s\")", remote_path);
if (handle == NULL) { if (handle == NULL) {
close(local_fd); close(local_fd);
buffer_free(&msg); buffer_free(&msg);
@ -1313,3 +1450,127 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
return status; return status;
} }
static int
upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
int pflag, int printflag, int depth)
{
int ret = 0, status;
DIR *dirp;
struct dirent *dp;
char *filename, *new_src, *new_dst;
struct stat sb;
Attrib a;
if (depth >= MAX_DIR_DEPTH) {
error("Maximum directory depth exceeded: %d levels", depth);
return -1;
}
if (stat(src, &sb) == -1) {
error("Couldn't stat directory \"%s\": %s",
src, strerror(errno));
return -1;
}
if (!S_ISDIR(sb.st_mode)) {
error("\"%s\" is not a directory", src);
return -1;
}
if (printflag)
printf("Entering %s\n", src);
attrib_clear(&a);
stat_to_attrib(&sb, &a);
a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
a.perm &= 01777;
if (!pflag)
a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
status = do_mkdir(conn, dst, &a, 0);
/*
* we lack a portable status for errno EEXIST,
* so if we get a SSH2_FX_FAILURE back we must check
* if it was created successfully.
*/
if (status != SSH2_FX_OK) {
if (status != SSH2_FX_FAILURE)
return -1;
if (do_stat(conn, dst, 0) == NULL)
return -1;
}
if ((dirp = opendir(src)) == NULL) {
error("Failed to open dir \"%s\": %s", src, strerror(errno));
return -1;
}
while (((dp = readdir(dirp)) != NULL) && !interrupted) {
if (dp->d_ino == 0)
continue;
filename = dp->d_name;
new_dst = path_append(dst, filename);
new_src = path_append(src, filename);
if (lstat(new_src, &sb) == -1) {
logit("%s: lstat failed: %s", filename,
strerror(errno));
ret = -1;
} else if (S_ISDIR(sb.st_mode)) {
if (strcmp(filename, ".") == 0 ||
strcmp(filename, "..") == 0)
continue;
if (upload_dir_internal(conn, new_src, new_dst,
pflag, depth + 1, printflag) == -1)
ret = -1;
} else if (S_ISREG(sb.st_mode)) {
if (do_upload(conn, new_src, new_dst, pflag) == -1) {
error("Uploading of file %s to %s failed!",
new_src, new_dst);
ret = -1;
}
} else
logit("%s: not a regular file\n", filename);
xfree(new_dst);
xfree(new_src);
}
do_setstat(conn, dst, &a);
(void) closedir(dirp);
return ret;
}
int
upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
int pflag)
{
char *dst_canon;
int ret;
if ((dst_canon = do_realpath(conn, dst)) == NULL) {
error("Unable to canonicalise path \"%s\"", dst);
return -1;
}
ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
xfree(dst_canon);
return ret;
}
char *
path_append(char *p1, char *p2)
{
char *ret;
size_t len = strlen(p1) + strlen(p2) + 2;
ret = xmalloc(len);
strlcpy(ret, p1, len);
if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
strlcat(ret, "/", len);
strlcat(ret, p2, len);
return(ret);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.17 2008/06/08 20:15:29 dtucker Exp $ */ /* $OpenBSD: sftp-client.h,v 1.18 2009/08/18 18:36:20 djm Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@ -68,7 +68,7 @@ void free_sftp_dirents(SFTP_DIRENT **);
int do_rm(struct sftp_conn *, char *); int do_rm(struct sftp_conn *, char *);
/* Create directory 'path' */ /* Create directory 'path' */
int do_mkdir(struct sftp_conn *, char *, Attrib *); int do_mkdir(struct sftp_conn *, char *, Attrib *, int);
/* Remove directory 'path' */ /* Remove directory 'path' */
int do_rmdir(struct sftp_conn *, char *); int do_rmdir(struct sftp_conn *, char *);
@ -103,7 +103,13 @@ int do_symlink(struct sftp_conn *, char *, char *);
* Download 'remote_path' to 'local_path'. Preserve permissions and times * Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set * if 'pflag' is set
*/ */
int do_download(struct sftp_conn *, char *, char *, int); int do_download(struct sftp_conn *, char *, char *, Attrib *, int);
/*
* Recursively download 'remote_directory' to 'local_directory'. Preserve
* times if 'pflag' is set
*/
int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int);
/* /*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times * Upload 'local_path' to 'remote_path'. Preserve permissions and times
@ -111,4 +117,13 @@ int do_download(struct sftp_conn *, char *, char *, int);
*/ */
int do_upload(struct sftp_conn *, char *, char *, int); int do_upload(struct sftp_conn *, char *, char *, int);
/*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
* times if 'pflag' is set
*/
int upload_dir(struct sftp_conn *, char *, char *, int, int);
/* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(char *, char *);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */ /* $OpenBSD: sftp-common.c,v 1.23 2010/01/15 09:24:23 markus Exp $ */
/* /*
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Damien Miller. All rights reserved. * Copyright (c) 2001 Damien Miller. All rights reserved.
@ -36,6 +36,9 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <stdarg.h> #include <stdarg.h>
#ifdef HAVE_UTIL_H
#include <util.h>
#endif
#include "xmalloc.h" #include "xmalloc.h"
#include "buffer.h" #include "buffer.h"
@ -184,24 +187,23 @@ fx2txt(int status)
* drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
*/ */
char * char *
ls_file(const char *name, const struct stat *st, int remote) ls_file(const char *name, const struct stat *st, int remote, int si_units)
{ {
int ulen, glen, sz = 0; int ulen, glen, sz = 0;
struct passwd *pw;
struct group *gr;
struct tm *ltime = localtime(&st->st_mtime); struct tm *ltime = localtime(&st->st_mtime);
char *user, *group; char *user, *group;
char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
char sbuf[FMT_SCALED_STRSIZE];
strmode(st->st_mode, mode); strmode(st->st_mode, mode);
if (!remote && (pw = getpwuid(st->st_uid)) != NULL) { if (!remote) {
user = pw->pw_name; user = user_from_uid(st->st_uid, 0);
} else { } else {
snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
user = ubuf; user = ubuf;
} }
if (!remote && (gr = getgrgid(st->st_gid)) != NULL) { if (!remote) {
group = gr->gr_name; group = group_from_gid(st->st_gid, 0);
} else { } else {
snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
group = gbuf; group = gbuf;
@ -216,8 +218,15 @@ ls_file(const char *name, const struct stat *st, int remote)
tbuf[0] = '\0'; tbuf[0] = '\0';
ulen = MAX(strlen(user), 8); ulen = MAX(strlen(user), 8);
glen = MAX(strlen(group), 8); glen = MAX(strlen(group), 8);
snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, if (si_units) {
(u_int)st->st_nlink, ulen, user, glen, group, fmt_scaled((long long)st->st_size, sbuf);
(unsigned long long)st->st_size, tbuf, name); snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8s %s %s", mode,
(u_int)st->st_nlink, ulen, user, glen, group,
sbuf, tbuf, name);
} else {
snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode,
(u_int)st->st_nlink, ulen, user, glen, group,
(unsigned long long)st->st_size, tbuf, name);
}
return xstrdup(buf); return xstrdup(buf);
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-common.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */ /* $OpenBSD: sftp-common.h,v 1.11 2010/01/13 01:40:16 djm Exp $ */
/* /*
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -46,6 +46,6 @@ void stat_to_attrib(const struct stat *, Attrib *);
void attrib_to_stat(const Attrib *, struct stat *); void attrib_to_stat(const Attrib *, struct stat *);
Attrib *decode_attrib(Buffer *); Attrib *decode_attrib(Buffer *);
void encode_attrib(Buffer *, const Attrib *); void encode_attrib(Buffer *, const Attrib *);
char *ls_file(const char *, const struct stat *, int); char *ls_file(const char *, const struct stat *, int, int);
const char *fx2txt(int); const char *fx2txt(int);

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: sftp-server.8,v 1.15 2009/03/26 08:38:39 sobrado Exp $ .\" $OpenBSD: sftp-server.8,v 1.19 2010/01/09 03:36:00 jmc Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.\" Copyright (c) 2000 Markus Friedl. All rights reserved. .\" Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -23,7 +23,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd March 26 2009 .Dd January 9 2010
.Dt SFTP-SERVER 8 .Dt SFTP-SERVER 8
.Os .Os
.Sh NAME .Sh NAME
@ -31,8 +31,10 @@
.Nd SFTP server subsystem .Nd SFTP server subsystem
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm sftp-server .Nm sftp-server
.Op Fl ehR
.Op Fl f Ar log_facility .Op Fl f Ar log_facility
.Op Fl l Ar log_level .Op Fl l Ar log_level
.Op Fl u Ar umask
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a program that speaks the server side of SFTP protocol is a program that speaks the server side of SFTP protocol
@ -55,12 +57,20 @@ for more information.
.Pp .Pp
Valid options are: Valid options are:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl e
Causes
.Nm
to print logging information to stderr instead of syslog for debugging.
.It Fl f Ar log_facility .It Fl f Ar log_facility
Specifies the facility code that is used when logging messages from Specifies the facility code that is used when logging messages from
.Nm . .Nm .
The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
The default is AUTH. The default is AUTH.
.It Fl h
Displays
.Nm
usage information.
.It Fl l Ar log_level .It Fl l Ar log_level
Specifies which messages will be logged by Specifies which messages will be logged by
.Nm . .Nm .
@ -72,6 +82,17 @@ performs on behalf of the client.
DEBUG and DEBUG1 are equivalent. DEBUG and DEBUG1 are equivalent.
DEBUG2 and DEBUG3 each specify higher levels of debugging output. DEBUG2 and DEBUG3 each specify higher levels of debugging output.
The default is ERROR. The default is ERROR.
.It Fl R
Places this instance of
.Nm
into a read-only mode.
Attempts to open files for writing, as well as other operations that change
the state of the filesystem, will be denied.
.It Fl u Ar umask
Sets an explicit
.Xr umask 2
to be applied to newly-created files and directories, instead of the
user's default mask.
.El .El
.Pp .Pp
For logging to work, For logging to work,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-server.c,v 1.85 2009/04/14 16:33:42 stevesk Exp $ */ /* $OpenBSD: sftp-server.c,v 1.91 2010/01/13 01:40:16 djm Exp $ */
/* /*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
* *
@ -70,6 +70,9 @@ Buffer oqueue;
/* Version of client */ /* Version of client */
int version; int version;
/* Disable writes */
int readonly;
/* portable attributes, etc. */ /* portable attributes, etc. */
typedef struct Stat Stat; typedef struct Stat Stat;
@ -553,16 +556,21 @@ process_open(void)
mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
logit("open \"%s\" flags %s mode 0%o", logit("open \"%s\" flags %s mode 0%o",
name, string_from_portable(pflags), mode); name, string_from_portable(pflags), mode);
fd = open(name, flags, mode); if (readonly &&
if (fd < 0) { ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
status = errno_to_portable(errno); status = SSH2_FX_PERMISSION_DENIED;
} else { else {
handle = handle_new(HANDLE_FILE, name, fd, NULL); fd = open(name, flags, mode);
if (handle < 0) { if (fd < 0) {
close(fd); status = errno_to_portable(errno);
} else { } else {
send_handle(id, handle); handle = handle_new(HANDLE_FILE, name, fd, NULL);
status = SSH2_FX_OK; if (handle < 0) {
close(fd);
} else {
send_handle(id, handle);
status = SSH2_FX_OK;
}
} }
} }
if (status != SSH2_FX_OK) if (status != SSH2_FX_OK)
@ -632,7 +640,7 @@ process_write(void)
u_int32_t id; u_int32_t id;
u_int64_t off; u_int64_t off;
u_int len; u_int len;
int handle, fd, ret, status = SSH2_FX_FAILURE; int handle, fd, ret, status;
char *data; char *data;
id = get_int(); id = get_int();
@ -643,7 +651,12 @@ process_write(void)
debug("request %u: write \"%s\" (handle %d) off %llu len %d", debug("request %u: write \"%s\" (handle %d) off %llu len %d",
id, handle_to_name(handle), handle, (unsigned long long)off, len); id, handle_to_name(handle), handle, (unsigned long long)off, len);
fd = handle_to_fd(handle); fd = handle_to_fd(handle);
if (fd >= 0) {
if (fd < 0)
status = SSH2_FX_FAILURE;
else if (readonly)
status = SSH2_FX_PERMISSION_DENIED;
else {
if (lseek(fd, off, SEEK_SET) < 0) { if (lseek(fd, off, SEEK_SET) < 0) {
status = errno_to_portable(errno); status = errno_to_portable(errno);
error("process_write: seek failed"); error("process_write: seek failed");
@ -658,6 +671,7 @@ process_write(void)
handle_update_write(handle, ret); handle_update_write(handle, ret);
} else { } else {
debug2("nothing at all written"); debug2("nothing at all written");
status = SSH2_FX_FAILURE;
} }
} }
} }
@ -754,6 +768,10 @@ process_setstat(void)
name = get_string(NULL); name = get_string(NULL);
a = get_attrib(); a = get_attrib();
debug("request %u: setstat name \"%s\"", id, name); debug("request %u: setstat name \"%s\"", id, name);
if (readonly) {
status = SSH2_FX_PERMISSION_DENIED;
a->flags = 0;
}
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
logit("set \"%s\" size %llu", logit("set \"%s\" size %llu",
name, (unsigned long long)a->size); name, (unsigned long long)a->size);
@ -802,9 +820,11 @@ process_fsetstat(void)
a = get_attrib(); a = get_attrib();
debug("request %u: fsetstat handle %d", id, handle); debug("request %u: fsetstat handle %d", id, handle);
fd = handle_to_fd(handle); fd = handle_to_fd(handle);
if (fd < 0) { if (fd < 0)
status = SSH2_FX_FAILURE; status = SSH2_FX_FAILURE;
} else { else if (readonly)
status = SSH2_FX_PERMISSION_DENIED;
else {
char *name = handle_to_name(handle); char *name = handle_to_name(handle);
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
@ -920,7 +940,7 @@ process_readdir(void)
continue; continue;
stat_to_attrib(&st, &(stats[count].attrib)); stat_to_attrib(&st, &(stats[count].attrib));
stats[count].name = xstrdup(dp->d_name); stats[count].name = xstrdup(dp->d_name);
stats[count].long_name = ls_file(dp->d_name, &st, 0); stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
count++; count++;
/* send up to 100 entries in one message */ /* send up to 100 entries in one message */
/* XXX check packet size instead */ /* XXX check packet size instead */
@ -952,8 +972,12 @@ process_remove(void)
name = get_string(NULL); name = get_string(NULL);
debug3("request %u: remove", id); debug3("request %u: remove", id);
logit("remove name \"%s\"", name); logit("remove name \"%s\"", name);
ret = unlink(name); if (readonly)
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; status = SSH2_FX_PERMISSION_DENIED;
else {
ret = unlink(name);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status); send_status(id, status);
xfree(name); xfree(name);
} }
@ -973,8 +997,12 @@ process_mkdir(void)
a->perm & 07777 : 0777; a->perm & 07777 : 0777;
debug3("request %u: mkdir", id); debug3("request %u: mkdir", id);
logit("mkdir name \"%s\" mode 0%o", name, mode); logit("mkdir name \"%s\" mode 0%o", name, mode);
ret = mkdir(name, mode); if (readonly)
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; status = SSH2_FX_PERMISSION_DENIED;
else {
ret = mkdir(name, mode);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status); send_status(id, status);
xfree(name); xfree(name);
} }
@ -990,8 +1018,12 @@ process_rmdir(void)
name = get_string(NULL); name = get_string(NULL);
debug3("request %u: rmdir", id); debug3("request %u: rmdir", id);
logit("rmdir name \"%s\"", name); logit("rmdir name \"%s\"", name);
ret = rmdir(name); if (readonly)
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; status = SSH2_FX_PERMISSION_DENIED;
else {
ret = rmdir(name);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status); send_status(id, status);
xfree(name); xfree(name);
} }
@ -1036,7 +1068,9 @@ process_rename(void)
debug3("request %u: rename", id); debug3("request %u: rename", id);
logit("rename old \"%s\" new \"%s\"", oldpath, newpath); logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
status = SSH2_FX_FAILURE; status = SSH2_FX_FAILURE;
if (lstat(oldpath, &sb) == -1) if (readonly)
status = SSH2_FX_PERMISSION_DENIED;
else if (lstat(oldpath, &sb) == -1)
status = errno_to_portable(errno); status = errno_to_portable(errno);
else if (S_ISREG(sb.st_mode)) { else if (S_ISREG(sb.st_mode)) {
/* Race-free rename of regular files */ /* Race-free rename of regular files */
@ -1120,8 +1154,12 @@ process_symlink(void)
debug3("request %u: symlink", id); debug3("request %u: symlink", id);
logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
/* this will fail if 'newpath' exists */ /* this will fail if 'newpath' exists */
ret = symlink(oldpath, newpath); if (readonly)
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; status = SSH2_FX_PERMISSION_DENIED;
else {
ret = symlink(oldpath, newpath);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status); send_status(id, status);
xfree(oldpath); xfree(oldpath);
xfree(newpath); xfree(newpath);
@ -1131,15 +1169,19 @@ static void
process_extended_posix_rename(u_int32_t id) process_extended_posix_rename(u_int32_t id)
{ {
char *oldpath, *newpath; char *oldpath, *newpath;
int ret, status;
oldpath = get_string(NULL); oldpath = get_string(NULL);
newpath = get_string(NULL); newpath = get_string(NULL);
debug3("request %u: posix-rename", id); debug3("request %u: posix-rename", id);
logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
if (rename(oldpath, newpath) == -1) if (readonly)
send_status(id, errno_to_portable(errno)); status = SSH2_FX_PERMISSION_DENIED;
else else {
send_status(id, SSH2_FX_OK); ret = rename(oldpath, newpath);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status);
xfree(oldpath); xfree(oldpath);
xfree(newpath); xfree(newpath);
} }
@ -1322,7 +1364,8 @@ sftp_server_usage(void)
extern char *__progname; extern char *__progname;
fprintf(stderr, fprintf(stderr,
"usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname); "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n",
__progname);
exit(1); exit(1);
} }
@ -1334,6 +1377,8 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
ssize_t len, olen, set_size; ssize_t len, olen, set_size;
SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
char *cp, buf[4*4096]; char *cp, buf[4*4096];
const char *errmsg;
mode_t mask;
extern char *optarg; extern char *optarg;
extern char *__progname; extern char *__progname;
@ -1341,8 +1386,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
__progname = ssh_get_progname(argv[0]); __progname = ssh_get_progname(argv[0]);
log_init(__progname, log_level, log_facility, log_stderr); log_init(__progname, log_level, log_facility, log_stderr);
while (!skipargs && (ch = getopt(argc, argv, "f:l:che")) != -1) { while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) {
switch (ch) { switch (ch) {
case 'R':
readonly = 1;
break;
case 'c': case 'c':
/* /*
* Ignore all arguments if we are invoked as a * Ignore all arguments if we are invoked as a
@ -1363,6 +1411,13 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
if (log_facility == SYSLOG_FACILITY_NOT_SET) if (log_facility == SYSLOG_FACILITY_NOT_SET)
error("Invalid log facility \"%s\"", optarg); error("Invalid log facility \"%s\"", optarg);
break; break;
case 'u':
mask = (mode_t)strtonum(optarg, 0, 0777, &errmsg);
if (errmsg != NULL)
fatal("Invalid umask \"%s\": %s",
optarg, errmsg);
(void)umask(mask);
break;
case 'h': case 'h':
default: default:
sftp_server_usage(); sftp_server_usage();
@ -1387,8 +1442,8 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
logit("session opened for local user %s from [%s]", logit("session opened for local user %s from [%s]",
pw->pw_name, client_addr); pw->pw_name, client_addr);
in = dup(STDIN_FILENO); in = STDIN_FILENO;
out = dup(STDOUT_FILENO); out = STDOUT_FILENO;
#ifdef HAVE_CYGWIN #ifdef HAVE_CYGWIN
setmode(in, O_BINARY); setmode(in, O_BINARY);

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.69 2008/12/09 15:35:00 sobrado Exp $ .\" $OpenBSD: sftp.1,v 1.83 2010/02/08 10:50:20 markus Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" Copyright (c) 2001 Damien Miller. All rights reserved.
@ -23,7 +23,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd December 9 2008 .Dd February 8 2010
.Dt SFTP 1 .Dt SFTP 1
.Os .Os
.Sh NAME .Sh NAME
@ -32,12 +32,15 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm sftp .Nm sftp
.Bk -words .Bk -words
.Op Fl 1Cv .Op Fl 1246Cpqrv
.Op Fl B Ar buffer_size .Op Fl B Ar buffer_size
.Op Fl b Ar batchfile .Op Fl b Ar batchfile
.Op Fl c Ar cipher
.Op Fl D Ar sftp_server_path
.Op Fl F Ar ssh_config .Op Fl F Ar ssh_config
.Op Fl i Ar identity_file
.Op Fl o Ar ssh_option .Op Fl o Ar ssh_option
.Op Fl P Ar sftp_server_path .Op Fl P Ar port
.Op Fl R Ar num_requests .Op Fl R Ar num_requests
.Op Fl S Ar program .Op Fl S Ar program
.Op Fl s Ar subsystem | sftp_server .Op Fl s Ar subsystem | sftp_server
@ -88,6 +91,16 @@ The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl 1 .It Fl 1
Specify the use of protocol version 1. Specify the use of protocol version 1.
.It Fl 2
Specify the use of protocol version 2.
.It Fl 4
Forces
.Nm
to use IPv4 addresses only.
.It Fl 6
Forces
.Nm
to use IPv6 addresses only.
.It Fl B Ar buffer_size .It Fl B Ar buffer_size
Specify the size of the buffer that Specify the size of the buffer that
.Nm .Nm
@ -125,12 +138,26 @@ character (for example,
Enables compression (via ssh's Enables compression (via ssh's
.Fl C .Fl C
flag). flag).
.It Fl c Ar cipher
Selects the cipher to use for encrypting the data transfers.
This option is directly passed to
.Xr ssh 1 .
.It Fl D Ar sftp_server_path
Connect directly to a local sftp server
(rather than via
.Xr ssh 1 ) .
This option may be useful in debugging the client and server.
.It Fl F Ar ssh_config .It Fl F Ar ssh_config
Specifies an alternative Specifies an alternative
per-user configuration file for per-user configuration file for
.Xr ssh 1 . .Xr ssh 1 .
This option is directly passed to This option is directly passed to
.Xr ssh 1 . .Xr ssh 1 .
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for public key
authentication is read.
This option is directly passed to
.Xr ssh 1 .
.It Fl o Ar ssh_option .It Fl o Ar ssh_option
Can be used to pass options to Can be used to pass options to
.Nm ssh .Nm ssh
@ -176,6 +203,7 @@ For full details of the options listed below, and their possible values, see
.It NoHostAuthenticationForLocalhost .It NoHostAuthenticationForLocalhost
.It NumberOfPasswordPrompts .It NumberOfPasswordPrompts
.It PasswordAuthentication .It PasswordAuthentication
.It PKCS11Provider
.It Port .It Port
.It PreferredAuthentications .It PreferredAuthentications
.It Protocol .It Protocol
@ -187,7 +215,6 @@ For full details of the options listed below, and their possible values, see
.It SendEnv .It SendEnv
.It ServerAliveInterval .It ServerAliveInterval
.It ServerAliveCountMax .It ServerAliveCountMax
.It SmartcardDevice
.It StrictHostKeyChecking .It StrictHostKeyChecking
.It TCPKeepAlive .It TCPKeepAlive
.It UsePrivilegedPort .It UsePrivilegedPort
@ -195,16 +222,25 @@ For full details of the options listed below, and their possible values, see
.It UserKnownHostsFile .It UserKnownHostsFile
.It VerifyHostKeyDNS .It VerifyHostKeyDNS
.El .El
.It Fl P Ar sftp_server_path .It Fl P Ar port
Connect directly to a local sftp server Specifies the port to connect to on the remote host.
(rather than via .It Fl p
.Xr ssh 1 ) . Preserves modification times, access times, and modes from the
This option may be useful in debugging the client and server. original files transferred.
.It Fl q
Quiet mode: disables the progress meter as well as warning and
diagnostic messages from
.Xr ssh 1 .
.It Fl R Ar num_requests .It Fl R Ar num_requests
Specify how many requests may be outstanding at any one time. Specify how many requests may be outstanding at any one time.
Increasing this may slightly improve file transfer speed Increasing this may slightly improve file transfer speed
but will increase memory usage. but will increase memory usage.
The default is 64 outstanding requests. The default is 64 outstanding requests.
.It Fl r
Recursively copy entire directories when uploading and downloading.
Note that
.Nm
does not follow symbolic links encountered in the tree traversal.
.It Fl S Ar program .It Fl S Ar program
Name of the Name of the
.Ar program .Ar program
@ -295,7 +331,7 @@ extension.
Quit Quit
.Nm sftp . .Nm sftp .
.It Xo Ic get .It Xo Ic get
.Op Fl P .Op Fl Ppr
.Ar remote-path .Ar remote-path
.Op Ar local-path .Op Ar local-path
.Xc .Xc
@ -314,10 +350,20 @@ If it does and
is specified, then is specified, then
.Ar local-path .Ar local-path
must specify a directory. must specify a directory.
If the .Pp
If either the
.Fl P .Fl P
or
.Fl p
flag is specified, then full file permissions and access times are flag is specified, then full file permissions and access times are
copied too. copied too.
.Pp
If the
.Fl r
flag is specified then directories will be copied recursively.
Note that
.Nm
does not follow symbolic links when performing recursive transfers.
.It Ic help .It Ic help
Display help text. Display help text.
.It Ic lcd Ar path .It Ic lcd Ar path
@ -348,7 +394,7 @@ to
.It Ic lpwd .It Ic lpwd
Print local working directory. Print local working directory.
.It Xo Ic ls .It Xo Ic ls
.Op Fl 1aflnrSt .Op Fl 1afhlnrSt
.Op Ar path .Op Ar path
.Xc .Xc
Display a remote directory listing of either Display a remote directory listing of either
@ -373,6 +419,11 @@ List files beginning with a dot
.It Fl f .It Fl f
Do not sort the listing. Do not sort the listing.
The default sort order is lexicographical. The default sort order is lexicographical.
.It Fl h
When used with a long format option, use unit suffixes: Byte, Kilobyte,
Megabyte, Gigabyte, Terabyte, Petabyte, and Exabyte in order to reduce
the number of digits to four or fewer using powers of 2 for sizes (K=1024,
M=1048576, etc.).
.It Fl l .It Fl l
Display additional details including permissions Display additional details including permissions
and ownership information. and ownership information.
@ -395,7 +446,7 @@ Create remote directory specified by
.It Ic progress .It Ic progress
Toggle display of progress meter. Toggle display of progress meter.
.It Xo Ic put .It Xo Ic put
.Op Fl P .Op Fl Ppr
.Ar local-path .Ar local-path
.Op Ar remote-path .Op Ar remote-path
.Xc .Xc
@ -413,10 +464,20 @@ If it does and
is specified, then is specified, then
.Ar remote-path .Ar remote-path
must specify a directory. must specify a directory.
If the .Pp
If ether the
.Fl P .Fl P
flag is specified, then the file's full permission and access time are or
.Fl p
flag is specified, then full file permissions and access times are
copied too. copied too.
.Pp
If the
.Fl r
flag is specified then directories will be copied recursively.
Note that
.Nm
does not follow symbolic links when performing recursive transfers.
.It Ic pwd .It Ic pwd
Display remote working directory. Display remote working directory.
.It Ic quit .It Ic quit

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-add.1,v 1.46 2007/06/12 13:41:03 jmc Exp $ .\" $OpenBSD: ssh-add.1,v 1.52 2010/03/05 10:28:21 djm Exp $
.\" .\"
.\" -*- nroff -*- .\" -*- nroff -*-
.\" .\"
@ -37,7 +37,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd June 12 2007 .Dd March 5 2010
.Dt SSH-ADD 1 .Dt SSH-ADD 1
.Os .Os
.Sh NAME .Sh NAME
@ -49,9 +49,9 @@
.Op Fl t Ar life .Op Fl t Ar life
.Op Ar .Op Ar
.Nm ssh-add .Nm ssh-add
.Fl s Ar reader .Fl s Ar pkcs11
.Nm ssh-add .Nm ssh-add
.Fl e Ar reader .Fl e Ar pkcs11
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
adds RSA or DSA identities to the authentication agent, adds RSA or DSA identities to the authentication agent,
@ -61,7 +61,14 @@ When run without arguments, it adds the files
.Pa ~/.ssh/id_dsa .Pa ~/.ssh/id_dsa
and and
.Pa ~/.ssh/identity . .Pa ~/.ssh/identity .
After loading a private key,
.Nm
will try to load corresponding certificate information from the
filename obtained by appending
.Pa -cert.pub
to the name of the private key file.
Alternative file names can be given on the command line. Alternative file names can be given on the command line.
.Pp
If any file requires a passphrase, If any file requires a passphrase,
.Nm .Nm
asks for the passphrase from the user. asks for the passphrase from the user.
@ -101,17 +108,17 @@ If no public key is found at a given path,
will append will append
.Pa .pub .Pa .pub
and retry. and retry.
.It Fl e Ar reader .It Fl e Ar pkcs11
Remove key in smartcard Remove keys provided by the PKCS#11 shared library
.Ar reader . .Ar pkcs11 .
.It Fl L .It Fl L
Lists public key parameters of all identities currently represented Lists public key parameters of all identities currently represented
by the agent. by the agent.
.It Fl l .It Fl l
Lists fingerprints of all identities currently represented by the agent. Lists fingerprints of all identities currently represented by the agent.
.It Fl s Ar reader .It Fl s Ar pkcs11
Add key in smartcard Add keys provided by the PKCS#11 shared library
.Ar reader . .Ar pkcs11 .
.It Fl t Ar life .It Fl t Ar life
Set a maximum lifetime when adding identities to an agent. Set a maximum lifetime when adding identities to an agent.
The lifetime may be specified in seconds or in a time format The lifetime may be specified in seconds or in a time format
@ -148,8 +155,9 @@ may be necessary to redirect the input from
.Pa /dev/null .Pa /dev/null
to make this work.) to make this work.)
.It Ev SSH_AUTH_SOCK .It Ev SSH_AUTH_SOCK
Identifies the path of a unix-domain socket used to communicate with the Identifies the path of a
agent. .Ux Ns -domain
socket used to communicate with the agent.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-add.c,v 1.90 2007/09/09 11:38:01 sobrado Exp $ */ /* $OpenBSD: ssh-add.c,v 1.94 2010/03/01 11:07:06 otto Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -138,9 +138,9 @@ delete_all(AuthenticationConnection *ac)
static int static int
add_file(AuthenticationConnection *ac, const char *filename) add_file(AuthenticationConnection *ac, const char *filename)
{ {
Key *private; Key *private, *cert;
char *comment = NULL; char *comment = NULL;
char msg[1024]; char msg[1024], *certpath;
int fd, perms_ok, ret = -1; int fd, perms_ok, ret = -1;
if ((fd = open(filename, O_RDONLY)) < 0) { if ((fd = open(filename, O_RDONLY)) < 0) {
@ -195,13 +195,37 @@ add_file(AuthenticationConnection *ac, const char *filename)
if (confirm != 0) if (confirm != 0)
fprintf(stderr, fprintf(stderr,
"The user has to confirm each use of the key\n"); "The user has to confirm each use of the key\n");
} else if (ssh_add_identity(ac, private, comment)) {
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
ret = 0;
} else { } else {
fprintf(stderr, "Could not add identity: %s\n", filename); fprintf(stderr, "Could not add identity: %s\n", filename);
} }
/* Now try to add the certificate flavour too */
xasprintf(&certpath, "%s-cert.pub", filename);
if ((cert = key_load_public(certpath, NULL)) != NULL) {
/* Graft with private bits */
if (key_to_certified(private) != 0)
fatal("%s: key_to_certified failed", __func__);
key_cert_copy(cert, private);
key_free(cert);
if (ssh_add_identity_constrained(ac, private, comment,
lifetime, confirm)) {
fprintf(stderr, "Certificate added: %s (%s)\n",
certpath, private->cert->key_id);
if (lifetime != 0)
fprintf(stderr, "Lifetime set to %d seconds\n",
lifetime);
if (confirm != 0)
fprintf(stderr, "The user has to confirm each "
"use of the key\n");
} else {
error("Certificate %s (%s) add failed", certpath,
private->cert->key_id);
}
}
xfree(certpath);
xfree(comment); xfree(comment);
key_free(private); key_free(private);
@ -214,7 +238,7 @@ update_card(AuthenticationConnection *ac, int add, const char *id)
char *pin; char *pin;
int ret = -1; int ret = -1;
pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN);
if (pin == NULL) if (pin == NULL)
return -1; return -1;
@ -320,10 +344,8 @@ usage(void)
fprintf(stderr, " -X Unlock agent.\n"); fprintf(stderr, " -X Unlock agent.\n");
fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n");
fprintf(stderr, " -c Require confirmation to sign using identities\n"); fprintf(stderr, " -c Require confirmation to sign using identities\n");
#ifdef SMARTCARD fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n");
fprintf(stderr, " -s reader Add key in smartcard reader.\n"); fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n");
fprintf(stderr, " -e reader Remove key in smartcard reader.\n");
#endif
} }
int int
@ -332,7 +354,7 @@ main(int argc, char **argv)
extern char *optarg; extern char *optarg;
extern int optind; extern int optind;
AuthenticationConnection *ac = NULL; AuthenticationConnection *ac = NULL;
char *sc_reader_id = NULL; char *pkcs11provider = NULL;
int i, ch, deleting = 0, ret = 0; int i, ch, deleting = 0, ret = 0;
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
@ -374,11 +396,11 @@ main(int argc, char **argv)
ret = 1; ret = 1;
goto done; goto done;
case 's': case 's':
sc_reader_id = optarg; pkcs11provider = optarg;
break; break;
case 'e': case 'e':
deleting = 1; deleting = 1;
sc_reader_id = optarg; pkcs11provider = optarg;
break; break;
case 't': case 't':
if ((lifetime = convtime(optarg)) == -1) { if ((lifetime = convtime(optarg)) == -1) {
@ -395,8 +417,8 @@ main(int argc, char **argv)
} }
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (sc_reader_id != NULL) { if (pkcs11provider != NULL) {
if (update_card(ac, !deleting, sc_reader_id) == -1) if (update_card(ac, !deleting, pkcs11provider) == -1)
ret = 1; ret = 1;
goto done; goto done;
} }

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-agent.1,v 1.47 2009/03/26 08:38:39 sobrado Exp $ .\" $OpenBSD: ssh-agent.1,v 1.50 2010/01/17 21:49:09 tedu Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi> .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd March 26 2009 .Dd January 17 2010
.Dt SSH-AGENT 1 .Dt SSH-AGENT 1
.Os .Os
.Sh NAME .Sh NAME
@ -68,7 +68,9 @@ machines using
The options are as follows: The options are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Fl a Ar bind_address .It Fl a Ar bind_address
Bind the agent to the unix-domain socket Bind the agent to the
.Ux Ns -domain
socket
.Ar bind_address . .Ar bind_address .
The default is The default is
.Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt . .Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt .
@ -118,8 +120,9 @@ and
.Pa ~/.ssh/identity . .Pa ~/.ssh/identity .
If the identity has a passphrase, If the identity has a passphrase,
.Xr ssh-add 1 .Xr ssh-add 1
asks for the passphrase (using a small X11 application if running asks for the passphrase on the terminal if it has one or from a small X11
under X11, or from the terminal if running without X). program if running under X11.
If neither of these is the case then the authentication will fail.
It then sends the identity to the agent. It then sends the identity to the agent.
Several identities can be stored in the Several identities can be stored in the
agent; the agent can automatically use any of these identities. agent; the agent can automatically use any of these identities.
@ -163,8 +166,9 @@ Instead, operations that require a private key will be performed
by the agent, and the result will be returned to the requester. by the agent, and the result will be returned to the requester.
This way, private keys are not exposed to clients using the agent. This way, private keys are not exposed to clients using the agent.
.Pp .Pp
A unix-domain socket is created A
and the name of this socket is stored in the .Ux Ns -domain
socket is created and the name of this socket is stored in the
.Ev SSH_AUTH_SOCK .Ev SSH_AUTH_SOCK
environment environment
variable. variable.
@ -187,8 +191,8 @@ Contains the protocol version 2 DSA authentication identity of the user.
.It Pa ~/.ssh/id_rsa .It Pa ~/.ssh/id_rsa
Contains the protocol version 2 RSA authentication identity of the user. Contains the protocol version 2 RSA authentication identity of the user.
.It Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt .It Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt
Unix-domain sockets used to contain the connection to the .Ux Ns -domain
authentication agent. sockets used to contain the connection to the authentication agent.
These sockets should only be readable by the owner. These sockets should only be readable by the owner.
The sockets should get automatically removed when the agent exits. The sockets should get automatically removed when the agent exits.
.El .El

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-agent.c,v 1.161 2009/03/23 19:38:04 tobias Exp $ */ /* $OpenBSD: ssh-agent.c,v 1.165 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -77,8 +77,8 @@ __RCSID("$FreeBSD$");
#include "log.h" #include "log.h"
#include "misc.h" #include "misc.h"
#ifdef SMARTCARD #ifdef ENABLE_PKCS11
#include "scard.h" #include "ssh-pkcs11.h"
#endif #endif
#if defined(HAVE_SYS_PRCTL_H) #if defined(HAVE_SYS_PRCTL_H)
@ -106,6 +106,7 @@ typedef struct identity {
TAILQ_ENTRY(identity) next; TAILQ_ENTRY(identity) next;
Key *key; Key *key;
char *comment; char *comment;
char *provider;
u_int death; u_int death;
u_int confirm; u_int confirm;
} Identity; } Identity;
@ -172,6 +173,8 @@ static void
free_identity(Identity *id) free_identity(Identity *id)
{ {
key_free(id->key); key_free(id->key);
if (id->provider != NULL)
xfree(id->provider);
xfree(id->comment); xfree(id->comment);
xfree(id); xfree(id);
} }
@ -466,6 +469,8 @@ process_add_identity(SocketEntry *e, int version)
int type, success = 0, death = 0, confirm = 0; int type, success = 0, death = 0, confirm = 0;
char *type_name, *comment; char *type_name, *comment;
Key *k = NULL; Key *k = NULL;
u_char *cert;
u_int len;
switch (version) { switch (version) {
case 1: case 1:
@ -496,6 +501,14 @@ process_add_identity(SocketEntry *e, int version)
buffer_get_bignum2(&e->request, k->dsa->pub_key); buffer_get_bignum2(&e->request, k->dsa->pub_key);
buffer_get_bignum2(&e->request, k->dsa->priv_key); buffer_get_bignum2(&e->request, k->dsa->priv_key);
break; break;
case KEY_DSA_CERT:
cert = buffer_get_string(&e->request, &len);
if ((k = key_from_blob(cert, len)) == NULL)
fatal("Certificate parse failed");
xfree(cert);
key_add_private(k);
buffer_get_bignum2(&e->request, k->dsa->priv_key);
break;
case KEY_RSA: case KEY_RSA:
k = key_new_private(type); k = key_new_private(type);
buffer_get_bignum2(&e->request, k->rsa->n); buffer_get_bignum2(&e->request, k->rsa->n);
@ -508,6 +521,17 @@ process_add_identity(SocketEntry *e, int version)
/* Generate additional parameters */ /* Generate additional parameters */
rsa_generate_additional_parameters(k->rsa); rsa_generate_additional_parameters(k->rsa);
break; break;
case KEY_RSA_CERT:
cert = buffer_get_string(&e->request, &len);
if ((k = key_from_blob(cert, len)) == NULL)
fatal("Certificate parse failed");
xfree(cert);
key_add_private(k);
buffer_get_bignum2(&e->request, k->rsa->d);
buffer_get_bignum2(&e->request, k->rsa->iqmp);
buffer_get_bignum2(&e->request, k->rsa->p);
buffer_get_bignum2(&e->request, k->rsa->q);
break;
default: default:
buffer_clear(&e->request); buffer_clear(&e->request);
goto send; goto send;
@ -517,6 +541,7 @@ process_add_identity(SocketEntry *e, int version)
/* enable blinding */ /* enable blinding */
switch (k->type) { switch (k->type) {
case KEY_RSA: case KEY_RSA:
case KEY_RSA_CERT:
case KEY_RSA1: case KEY_RSA1:
if (RSA_blinding_on(k->rsa, NULL) != 1) { if (RSA_blinding_on(k->rsa, NULL) != 1) {
error("process_add_identity: RSA_blinding_on failed"); error("process_add_identity: RSA_blinding_on failed");
@ -550,7 +575,7 @@ process_add_identity(SocketEntry *e, int version)
if (lifetime && !death) if (lifetime && !death)
death = time(NULL) + lifetime; death = time(NULL) + lifetime;
if ((id = lookup_identity(k, version)) == NULL) { if ((id = lookup_identity(k, version)) == NULL) {
id = xmalloc(sizeof(Identity)); id = xcalloc(1, sizeof(Identity));
id->key = k; id->key = k;
TAILQ_INSERT_TAIL(&tab->idlist, id, next); TAILQ_INSERT_TAIL(&tab->idlist, id, next);
/* Increment the number of identities. */ /* Increment the number of identities. */
@ -610,17 +635,17 @@ no_identities(SocketEntry *e, u_int type)
buffer_free(&msg); buffer_free(&msg);
} }
#ifdef SMARTCARD #ifdef ENABLE_PKCS11
static void static void
process_add_smartcard_key(SocketEntry *e) process_add_smartcard_key(SocketEntry *e)
{ {
char *sc_reader_id = NULL, *pin; char *provider = NULL, *pin;
int i, type, version, success = 0, death = 0, confirm = 0; int i, type, version, count = 0, success = 0, death = 0, confirm = 0;
Key **keys, *k; Key **keys = NULL, *k;
Identity *id; Identity *id;
Idtab *tab; Idtab *tab;
sc_reader_id = buffer_get_string(&e->request, NULL); provider = buffer_get_string(&e->request, NULL);
pin = buffer_get_string(&e->request, NULL); pin = buffer_get_string(&e->request, NULL);
while (buffer_len(&e->request)) { while (buffer_len(&e->request)) {
@ -634,30 +659,22 @@ process_add_smartcard_key(SocketEntry *e)
default: default:
error("process_add_smartcard_key: " error("process_add_smartcard_key: "
"Unknown constraint type %d", type); "Unknown constraint type %d", type);
xfree(sc_reader_id);
xfree(pin);
goto send; goto send;
} }
} }
if (lifetime && !death) if (lifetime && !death)
death = time(NULL) + lifetime; death = time(NULL) + lifetime;
keys = sc_get_keys(sc_reader_id, pin); count = pkcs11_add_provider(provider, pin, &keys);
xfree(sc_reader_id); for (i = 0; i < count; i++) {
xfree(pin);
if (keys == NULL || keys[0] == NULL) {
error("sc_get_keys failed");
goto send;
}
for (i = 0; keys[i] != NULL; i++) {
k = keys[i]; k = keys[i];
version = k->type == KEY_RSA1 ? 1 : 2; version = k->type == KEY_RSA1 ? 1 : 2;
tab = idtab_lookup(version); tab = idtab_lookup(version);
if (lookup_identity(k, version) == NULL) { if (lookup_identity(k, version) == NULL) {
id = xmalloc(sizeof(Identity)); id = xcalloc(1, sizeof(Identity));
id->key = k; id->key = k;
id->comment = sc_get_key_label(k); id->provider = xstrdup(provider);
id->comment = xstrdup(provider); /* XXX */
id->death = death; id->death = death;
id->confirm = confirm; id->confirm = confirm;
TAILQ_INSERT_TAIL(&tab->idlist, id, next); TAILQ_INSERT_TAIL(&tab->idlist, id, next);
@ -668,8 +685,13 @@ process_add_smartcard_key(SocketEntry *e)
} }
keys[i] = NULL; keys[i] = NULL;
} }
xfree(keys);
send: send:
if (pin)
xfree(pin);
if (provider)
xfree(provider);
if (keys)
xfree(keys);
buffer_put_int(&e->output, 1); buffer_put_int(&e->output, 1);
buffer_put_char(&e->output, buffer_put_char(&e->output,
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
@ -678,42 +700,37 @@ process_add_smartcard_key(SocketEntry *e)
static void static void
process_remove_smartcard_key(SocketEntry *e) process_remove_smartcard_key(SocketEntry *e)
{ {
char *sc_reader_id = NULL, *pin; char *provider = NULL, *pin = NULL;
int i, version, success = 0; int version, success = 0;
Key **keys, *k = NULL; Identity *id, *nxt;
Identity *id;
Idtab *tab; Idtab *tab;
sc_reader_id = buffer_get_string(&e->request, NULL); provider = buffer_get_string(&e->request, NULL);
pin = buffer_get_string(&e->request, NULL); pin = buffer_get_string(&e->request, NULL);
keys = sc_get_keys(sc_reader_id, pin);
xfree(sc_reader_id);
xfree(pin); xfree(pin);
if (keys == NULL || keys[0] == NULL) { for (version = 1; version < 3; version++) {
error("sc_get_keys failed"); tab = idtab_lookup(version);
goto send; for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
} nxt = TAILQ_NEXT(id, next);
for (i = 0; keys[i] != NULL; i++) { if (!strcmp(provider, id->provider)) {
k = keys[i]; TAILQ_REMOVE(&tab->idlist, id, next);
version = k->type == KEY_RSA1 ? 1 : 2; free_identity(id);
if ((id = lookup_identity(k, version)) != NULL) { tab->nentries--;
tab = idtab_lookup(version); }
TAILQ_REMOVE(&tab->idlist, id, next);
tab->nentries--;
free_identity(id);
success = 1;
} }
key_free(k);
keys[i] = NULL;
} }
xfree(keys); if (pkcs11_del_provider(provider) == 0)
send: success = 1;
else
error("process_remove_smartcard_key:"
" pkcs11_del_provider failed");
xfree(provider);
buffer_put_int(&e->output, 1); buffer_put_int(&e->output, 1);
buffer_put_char(&e->output, buffer_put_char(&e->output,
success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
} }
#endif /* SMARTCARD */ #endif /* ENABLE_PKCS11 */
/* dispatch incoming messages */ /* dispatch incoming messages */
@ -798,7 +815,7 @@ process_message(SocketEntry *e)
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
process_remove_all_identities(e, 2); process_remove_all_identities(e, 2);
break; break;
#ifdef SMARTCARD #ifdef ENABLE_PKCS11
case SSH_AGENTC_ADD_SMARTCARD_KEY: case SSH_AGENTC_ADD_SMARTCARD_KEY:
case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
process_add_smartcard_key(e); process_add_smartcard_key(e);
@ -806,7 +823,7 @@ process_message(SocketEntry *e)
case SSH_AGENTC_REMOVE_SMARTCARD_KEY: case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
process_remove_smartcard_key(e); process_remove_smartcard_key(e);
break; break;
#endif /* SMARTCARD */ #endif /* ENABLE_PKCS11 */
default: default:
/* Unknown message. Respond with failure. */ /* Unknown message. Respond with failure. */
error("Unknown message %d", type); error("Unknown message %d", type);
@ -920,11 +937,11 @@ after_select(fd_set *readset, fd_set *writeset)
socklen_t slen; socklen_t slen;
char buf[1024]; char buf[1024];
int len, sock; int len, sock;
u_int i; u_int i, orig_alloc;
uid_t euid; uid_t euid;
gid_t egid; gid_t egid;
for (i = 0; i < sockets_alloc; i++) for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++)
switch (sockets[i].type) { switch (sockets[i].type) {
case AUTH_UNUSED: case AUTH_UNUSED:
break; break;
@ -957,16 +974,13 @@ after_select(fd_set *readset, fd_set *writeset)
case AUTH_CONNECTION: case AUTH_CONNECTION:
if (buffer_len(&sockets[i].output) > 0 && if (buffer_len(&sockets[i].output) > 0 &&
FD_ISSET(sockets[i].fd, writeset)) { FD_ISSET(sockets[i].fd, writeset)) {
do { len = write(sockets[i].fd,
len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
buffer_ptr(&sockets[i].output), buffer_len(&sockets[i].output));
buffer_len(&sockets[i].output)); if (len == -1 && (errno == EAGAIN ||
if (len == -1 && (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINTR || errno == EINTR))
errno == EWOULDBLOCK)) continue;
continue;
break;
} while (1);
if (len <= 0) { if (len <= 0) {
close_socket(&sockets[i]); close_socket(&sockets[i]);
break; break;
@ -974,14 +988,11 @@ after_select(fd_set *readset, fd_set *writeset)
buffer_consume(&sockets[i].output, len); buffer_consume(&sockets[i].output, len);
} }
if (FD_ISSET(sockets[i].fd, readset)) { if (FD_ISSET(sockets[i].fd, readset)) {
do { len = read(sockets[i].fd, buf, sizeof(buf));
len = read(sockets[i].fd, buf, sizeof(buf)); if (len == -1 && (errno == EAGAIN ||
if (len == -1 && (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINTR || errno == EINTR))
errno == EWOULDBLOCK)) continue;
continue;
break;
} while (1);
if (len <= 0) { if (len <= 0) {
close_socket(&sockets[i]); close_socket(&sockets[i]);
break; break;
@ -1016,6 +1027,9 @@ static void
cleanup_handler(int sig) cleanup_handler(int sig)
{ {
cleanup_socket(); cleanup_socket();
#ifdef ENABLE_PKCS11
pkcs11_terminate();
#endif
_exit(2); _exit(2);
} }
@ -1263,6 +1277,10 @@ main(int ac, char **av)
#endif #endif
skip: skip:
#ifdef ENABLE_PKCS11
pkcs11_init(0);
#endif
new_socket(AUTH_SOCKET, sock); new_socket(AUTH_SOCKET, sock);
if (ac > 0) if (ac > 0)
parent_alive_interval = 10; parent_alive_interval = 10;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-dss.c,v 1.24 2006/11/06 21:25:28 markus Exp $ */ /* $OpenBSD: ssh-dss.c,v 1.25 2010/02/26 20:29:54 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -53,7 +53,9 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp,
u_int rlen, slen, len, dlen; u_int rlen, slen, len, dlen;
Buffer b; Buffer b;
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { if (key == NULL ||
(key->type != KEY_DSA && key->type != KEY_DSA_CERT) ||
key->dsa == NULL) {
error("ssh_dss_sign: no DSA key"); error("ssh_dss_sign: no DSA key");
return -1; return -1;
} }
@ -116,7 +118,9 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen,
int rlen, ret; int rlen, ret;
Buffer b; Buffer b;
if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { if (key == NULL ||
(key->type != KEY_DSA && key->type != KEY_DSA_CERT) ||
key->dsa == NULL) {
error("ssh_dss_verify: no DSA key"); error("ssh_dss_verify: no DSA key");
return -1; return -1;
} }

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.79 2008/07/24 23:55:30 sthen Exp $ .\" $OpenBSD: ssh-keygen.1,v 1.88 2010/03/08 00:28:55 djm Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.\" -*- nroff -*- .\" -*- nroff -*-
@ -38,7 +38,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd July 24 2008 .Dd March 8 2010
.Dt SSH-KEYGEN 1 .Dt SSH-KEYGEN 1
.Os .Os
.Sh NAME .Sh NAME
@ -53,7 +53,6 @@
.Op Fl N Ar new_passphrase .Op Fl N Ar new_passphrase
.Op Fl C Ar comment .Op Fl C Ar comment
.Op Fl f Ar output_keyfile .Op Fl f Ar output_keyfile
.Ek
.Nm ssh-keygen .Nm ssh-keygen
.Fl p .Fl p
.Op Fl P Ar old_passphrase .Op Fl P Ar old_passphrase
@ -80,7 +79,7 @@
.Fl B .Fl B
.Op Fl f Ar input_keyfile .Op Fl f Ar input_keyfile
.Nm ssh-keygen .Nm ssh-keygen
.Fl D Ar reader .Fl D Ar pkcs11
.Nm ssh-keygen .Nm ssh-keygen
.Fl F Ar hostname .Fl F Ar hostname
.Op Fl f Ar known_hosts_file .Op Fl f Ar known_hosts_file
@ -92,9 +91,6 @@
.Fl R Ar hostname .Fl R Ar hostname
.Op Fl f Ar known_hosts_file .Op Fl f Ar known_hosts_file
.Nm ssh-keygen .Nm ssh-keygen
.Fl U Ar reader
.Op Fl f Ar input_keyfile
.Nm ssh-keygen
.Fl r Ar hostname .Fl r Ar hostname
.Op Fl f Ar input_keyfile .Op Fl f Ar input_keyfile
.Op Fl g .Op Fl g
@ -110,6 +106,18 @@
.Op Fl v .Op Fl v
.Op Fl a Ar num_trials .Op Fl a Ar num_trials
.Op Fl W Ar generator .Op Fl W Ar generator
.Nm ssh-keygen
.Fl s Ar ca_key
.Fl I Ar certificate_identity
.Op Fl h
.Op Fl n Ar principals
.Op Fl O Ar constraint
.Op Fl V Ar validity_interval
.Ar
.Nm ssh-keygen
.Fl L
.Op Fl f Ar input_keyfile
.Ek
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
generates, manages and converts authentication keys for generates, manages and converts authentication keys for
@ -202,9 +210,9 @@ Requests changing the comment in the private and public key files.
This operation is only supported for RSA1 keys. This operation is only supported for RSA1 keys.
The program will prompt for the file containing the private keys, for The program will prompt for the file containing the private keys, for
the passphrase if the key has one, and for the new comment. the passphrase if the key has one, and for the new comment.
.It Fl D Ar reader .It Fl D Ar pkcs11
Download the RSA public key stored in the smartcard in Download the RSA public keys provided by the PKCS#11 shared library
.Ar reader . .Ar pkcs11 .
.It Fl e .It Fl e
This option will read a private or public OpenSSH key file and This option will read a private or public OpenSSH key file and
print the key in print the key in
@ -249,6 +257,17 @@ but they do not reveal identifying information should the file's contents
be disclosed. be disclosed.
This option will not modify existing hashed hostnames and is therefore safe This option will not modify existing hashed hostnames and is therefore safe
to use on files that mix hashed and non-hashed names. to use on files that mix hashed and non-hashed names.
.It Fl h
When signing a key, create a host certificate instead of a user
certificate.
Please see the
.Sx CERTIFICATES
section for details.
.It Fl I Ar certificate_identity
Specify the key identity when signing a public key.
Please see the
.Sx CERTIFICATES
section for details.
.It Fl i .It Fl i
This option will read an unencrypted private (or public) key file This option will read an unencrypted private (or public) key file
in SSH2-compatible format and print an OpenSSH compatible private in SSH2-compatible format and print an OpenSSH compatible private
@ -258,6 +277,8 @@ also reads the
RFC 4716 SSH Public Key File Format. RFC 4716 SSH Public Key File Format.
This option allows importing keys from several commercial This option allows importing keys from several commercial
SSH implementations. SSH implementations.
.It Fl L
Prints the contents of a certificate.
.It Fl l .It Fl l
Show fingerprint of specified public key file. Show fingerprint of specified public key file.
Private RSA1 keys are also supported. Private RSA1 keys are also supported.
@ -272,6 +293,71 @@ Specify the amount of memory to use (in megabytes) when generating
candidate moduli for DH-GEX. candidate moduli for DH-GEX.
.It Fl N Ar new_passphrase .It Fl N Ar new_passphrase
Provides the new passphrase. Provides the new passphrase.
.It Fl n Ar principals
Specify one or more principals (user or host names) to be included in
a certificate when signing a key.
Multiple principals may be specified, separated by commas.
Please see the
.Sx CERTIFICATES
section for details.
.It Fl O Ar constraint
Specify a certificate constraint when signing a key.
This option may be specified multiple times.
Please see the
.Sx CERTIFICATES
section for details.
The constraints that are valid for user certificates are:
.Bl -tag -width Ds
.It Ic no-x11-forwarding
Disable X11 forwarding (permitted by default).
.It Ic no-agent-forwarding
Disable
.Xr ssh-agent 1
forwarding (permitted by default).
.It Ic no-port-forwarding
Disable port forwarding (permitted by default).
.It Ic no-pty
Disable PTY allocation (permitted by default).
.It Ic no-user-rc
Disable execution of
.Pa ~/.ssh/rc
by
.Xr sshd 8
(permitted by default).
.It Ic clear
Clear all enabled permissions.
This is useful for clearing the default set of permissions so permissions may
be added individually.
.It Ic permit-x11-forwarding
Allows X11 forwarding.
.It Ic permit-agent-forwarding
Allows
.Xr ssh-agent 1
forwarding.
.It Ic permit-port-forwarding
Allows port forwarding.
.It Ic permit-pty
Allows PTY allocation.
.It Ic permit-user-rc
Allows execution of
.Pa ~/.ssh/rc
by
.Xr sshd 8 .
.It Ic force-command=command
Forces the execution of
.Ar command
instead of any shell or command specified by the user when
the certificate is used for authentication.
.It Ic source-address=address_list
Restrict the source addresses from which the certificate is considered valid
from.
The
.Ar address_list
is a comma-separated list of one or more address/netmask pairs in CIDR
format.
.El
.Pp
At present, no constraints are valid for host keys.
.It Fl P Ar passphrase .It Fl P Ar passphrase
Provides the (old) passphrase. Provides the (old) passphrase.
.It Fl p .It Fl p
@ -301,6 +387,11 @@ Print the SSHFP fingerprint resource record named
for the specified public key file. for the specified public key file.
.It Fl S Ar start .It Fl S Ar start
Specify start point (in hex) when generating candidate moduli for DH-GEX. Specify start point (in hex) when generating candidate moduli for DH-GEX.
.It Fl s Ar ca_key
Certify (sign) a public key using the specified CA key.
Please see the
.Sx CERTIFICATES
section for details.
.It Fl T Ar output_file .It Fl T Ar output_file
Test DH group exchange candidate primes (generated using the Test DH group exchange candidate primes (generated using the
.Fl G .Fl G
@ -314,9 +405,29 @@ for protocol version 1 and
or or
.Dq dsa .Dq dsa
for protocol version 2. for protocol version 2.
.It Fl U Ar reader .It Fl V Ar validity_interval
Upload an existing RSA private key into the smartcard in Specify a validity interval when signing a certificate.
.Ar reader . A validity interval may consist of a single time, indicating that the
certificate is valid beginning now and expiring at that time, or may consist
of two times separated by a colon to indicate an explicit time interval.
The start time may be specified as a date in YYYYMMDD format, a time
in YYYYMMDDHHMMSS format or a relative time (to the current time) consisting
of a minus sign followed by a relative time in the format described in the
.Sx TIME FORMATS
section of
.Xr ssh_config 5 .
The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time or
a relative time starting with a plus character.
.Pp
For example:
.Dq +52w1d
(valid from now to 52 weeks and one day from now),
.Dq -4w:+4w
(valid from four weeks ago to four weeks from now),
.Dq 20100101123000:20110101123000
(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011),
.Dq -1d:20110101
(valid from yesterday to midnight, January 1st, 2011).
.It Fl v .It Fl v
Verbose mode. Verbose mode.
Causes Causes
@ -387,6 +498,73 @@ Screened DH groups may be installed in
.Pa /etc/moduli . .Pa /etc/moduli .
It is important that this file contains moduli of a range of bit lengths and It is important that this file contains moduli of a range of bit lengths and
that both ends of a connection share common moduli. that both ends of a connection share common moduli.
.Sh CERTIFICATES
.Nm
supports signing of keys to produce certificates that may be used for
user or host authentication.
Certificates consist of a public key, some identity information, zero or
more principal (user or host) names and an optional set of constraints that
are signed by a Certification Authority (CA) key.
Clients or servers may then trust only the CA key and verify its signature
on a certificate rather than trusting many user/host keys.
Note that OpenSSH certificates are a different, and much simpler, format to
the X.509 certificates used in
.Xr ssl 8 .
.Pp
.Nm
supports two types of certificates: user and host.
User certificates authenticate users to servers, whereas host certificates
authenticate server hosts to users.
To generate a user certificate:
.Pp
.Dl $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
.Pp
The resultant certificate will be placed in
.Pa /path/to/user_key_cert.pub .
A host certificate requires the
.Fl h
option:
.Pp
.Dl $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
.Pp
The host certificate will be output to
.Pa /path/to/host_key_cert.pub .
In both cases,
.Ar key_id
is a "key identifier" that is logged by the server when the certificate
is used for authentication.
.Pp
Certificates may be limited to be valid for a set of principal (user/host)
names.
By default, generated certificates are valid for all users or hosts.
To generate a certificate for a specified set of principals:
.Pp
.Dl $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
.Dl $ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub
.Pp
Additional limitations on the validity and use of user certificates may
be specified through certificate constraints.
A constrained certificate may disable features of the SSH session, may be
valid only when presented from particular source addresses or may
force the use of a specific command.
For a list of valid certificate constraints, see the documentation for the
.Fl O
option above.
.Pp
Finally, certificates may be defined with a validity lifetime.
The
.Fl V
option allows specification of certificate start and end times.
A certificate that is presented at a time outside this range will not be
considered valid.
By default, certificates have a maximum validity interval.
.Pp
For certificates to be used for user or host authentication, the CA
public key must be trusted by
.Xr sshd 8
or
.Xr ssh 1 .
Please refer to those manual pages for details.
.Sh FILES .Sh FILES
.Bl -tag -width Ds .Bl -tag -width Ds
.It Pa ~/.ssh/identity .It Pa ~/.ssh/identity
@ -394,7 +572,7 @@ Contains the protocol version 1 RSA authentication identity of the user.
This file should not be readable by anyone but the user. This file should not be readable by anyone but the user.
It is possible to It is possible to
specify a passphrase when generating the key; that passphrase will be specify a passphrase when generating the key; that passphrase will be
used to encrypt the private part of this file using 3DES. used to encrypt the private part of this file using 128-bit AES.
This file is not automatically accessed by This file is not automatically accessed by
.Nm .Nm
but it is offered as the default file for the private key. but it is offered as the default file for the private key.
@ -412,7 +590,7 @@ Contains the protocol version 2 DSA authentication identity of the user.
This file should not be readable by anyone but the user. This file should not be readable by anyone but the user.
It is possible to It is possible to
specify a passphrase when generating the key; that passphrase will be specify a passphrase when generating the key; that passphrase will be
used to encrypt the private part of this file using 3DES. used to encrypt the private part of this file using 128-bit AES.
This file is not automatically accessed by This file is not automatically accessed by
.Nm .Nm
but it is offered as the default file for the private key. but it is offered as the default file for the private key.
@ -430,7 +608,7 @@ Contains the protocol version 2 RSA authentication identity of the user.
This file should not be readable by anyone but the user. This file should not be readable by anyone but the user.
It is possible to It is possible to
specify a passphrase when generating the key; that passphrase will be specify a passphrase when generating the key; that passphrase will be
used to encrypt the private part of this file using 3DES. used to encrypt the private part of this file using 128-bit AES.
This file is not automatically accessed by This file is not automatically accessed by
.Nm .Nm
but it is offered as the default file for the private key. but it is offered as the default file for the private key.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.174 2009/06/22 05:39:28 dtucker Exp $ */ /* $OpenBSD: ssh-keygen.c,v 1.184 2010/03/07 22:16:01 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -48,9 +48,10 @@
#include "match.h" #include "match.h"
#include "hostfile.h" #include "hostfile.h"
#include "dns.h" #include "dns.h"
#include "ssh2.h"
#ifdef SMARTCARD #ifdef ENABLE_PKCS11
#include "scard.h" #include "ssh-pkcs11.h"
#endif #endif
/* Number of bits in the RSA/DSA key. This value can be set on the command line. */ /* Number of bits in the RSA/DSA key. This value can be set on the command line. */
@ -81,6 +82,9 @@ int find_host = 0;
/* Flag indicating that we want to delete a host from a known_hosts file */ /* Flag indicating that we want to delete a host from a known_hosts file */
int delete_host = 0; int delete_host = 0;
/* Flag indicating that we want to show the contents of a certificate */
int show_cert = 0;
/* Flag indicating that we just want to see the key fingerprint */ /* Flag indicating that we just want to see the key fingerprint */
int print_fingerprint = 0; int print_fingerprint = 0;
int print_bubblebabble = 0; int print_bubblebabble = 0;
@ -98,6 +102,35 @@ char *identity_new_passphrase = NULL;
/* This is set to the new comment if given on the command line. */ /* This is set to the new comment if given on the command line. */
char *identity_comment = NULL; char *identity_comment = NULL;
/* Path to CA key when certifying keys. */
char *ca_key_path = NULL;
/* Key type when certifying */
u_int cert_key_type = SSH2_CERT_TYPE_USER;
/* "key ID" of signed key */
char *cert_key_id = NULL;
/* Comma-separated list of principal names for certifying keys */
char *cert_principals = NULL;
/* Validity period for certificates */
u_int64_t cert_valid_from = 0;
u_int64_t cert_valid_to = ~0ULL;
/* Certificate constraints */
#define CONSTRAINT_X_FWD (1)
#define CONSTRAINT_AGENT_FWD (1<<1)
#define CONSTRAINT_PORT_FWD (1<<2)
#define CONSTRAINT_PTY (1<<3)
#define CONSTRAINT_USER_RC (1<<4)
#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \
CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \
CONSTRAINT_USER_RC)
u_int32_t constraint_flags = CONSTRAINT_DEFAULT;
char *constraint_command = NULL;
char *constraint_src_addr = NULL;
/* Dump public key file in format used by real and the original SSH 2 */ /* Dump public key file in format used by real and the original SSH 2 */
int convert_to_ssh2 = 0; int convert_to_ssh2 = 0;
int convert_from_ssh2 = 0; int convert_from_ssh2 = 0;
@ -181,6 +214,7 @@ do_convert_to_ssh2(struct passwd *pw)
Key *k; Key *k;
u_int len; u_int len;
u_char *blob; u_char *blob;
char comment[61];
struct stat st; struct stat st;
if (!have_identity) if (!have_identity)
@ -203,11 +237,14 @@ do_convert_to_ssh2(struct passwd *pw)
fprintf(stderr, "key_to_blob failed\n"); fprintf(stderr, "key_to_blob failed\n");
exit(1); exit(1);
} }
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */
fprintf(stdout, snprintf(comment, sizeof(comment),
"Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n", "%u-bit %s, converted by %s@%s from OpenSSH",
key_size(k), key_type(k), key_size(k), key_type(k),
pw->pw_name, hostname); pw->pw_name, hostname);
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
fprintf(stdout, "Comment: \"%s\"\n", comment);
dump_base64(stdout, blob, len); dump_base64(stdout, blob, len);
fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
key_free(k); key_free(k);
@ -455,51 +492,29 @@ do_print_public(struct passwd *pw)
exit(0); exit(0);
} }
#ifdef SMARTCARD
static void static void
do_upload(struct passwd *pw, const char *sc_reader_id) do_download(struct passwd *pw, char *pkcs11provider)
{
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);
logit("loading key done");
exit(0);
}
static void
do_download(struct passwd *pw, const char *sc_reader_id)
{ {
#ifdef ENABLE_PKCS11
Key **keys = NULL; Key **keys = NULL;
int i; int i, nkeys;
keys = sc_get_keys(sc_reader_id, NULL); pkcs11_init(0);
if (keys == NULL) nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys);
fatal("cannot read public key from smartcard"); if (nkeys <= 0)
for (i = 0; keys[i]; i++) { fatal("cannot read public key from pkcs11");
for (i = 0; i < nkeys; i++) {
key_write(keys[i], stdout); key_write(keys[i], stdout);
key_free(keys[i]); key_free(keys[i]);
fprintf(stdout, "\n"); fprintf(stdout, "\n");
} }
xfree(keys); xfree(keys);
pkcs11_terminate();
exit(0); exit(0);
#else
fatal("no pkcs11 support");
#endif /* ENABLE_PKCS11 */
} }
#endif /* SMARTCARD */
static void static void
do_fingerprint(struct passwd *pw) do_fingerprint(struct passwd *pw)
@ -524,7 +539,7 @@ do_fingerprint(struct passwd *pw)
public = key_load_public(identity_file, &comment); public = key_load_public(identity_file, &comment);
if (public != NULL) { if (public != NULL) {
fp = key_fingerprint(public, fptype, rep); fp = key_fingerprint(public, fptype, rep);
ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
printf("%u %s %s (%s)\n", key_size(public), fp, comment, printf("%u %s %s (%s)\n", key_size(public), fp, comment,
key_type(public)); key_type(public));
if (log_level >= SYSLOG_LEVEL_VERBOSE) if (log_level >= SYSLOG_LEVEL_VERBOSE)
@ -589,7 +604,7 @@ do_fingerprint(struct passwd *pw)
} }
comment = *cp ? cp : comment; comment = *cp ? cp : comment;
fp = key_fingerprint(public, fptype, rep); fp = key_fingerprint(public, fptype, rep);
ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
printf("%u %s %s (%s)\n", key_size(public), fp, printf("%u %s %s (%s)\n", key_size(public), fp,
comment ? comment : "no comment", key_type(public)); comment ? comment : "no comment", key_type(public));
if (log_level >= SYSLOG_LEVEL_VERBOSE) if (log_level >= SYSLOG_LEVEL_VERBOSE)
@ -609,7 +624,7 @@ do_fingerprint(struct passwd *pw)
} }
static void static void
print_host(FILE *f, const char *name, Key *public, int hash) printhost(FILE *f, const char *name, Key *public, int ca, int hash)
{ {
if (print_fingerprint) { if (print_fingerprint) {
enum fp_rep rep; enum fp_rep rep;
@ -619,7 +634,7 @@ print_host(FILE *f, const char *name, Key *public, int hash)
fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
fp = key_fingerprint(public, fptype, rep); fp = key_fingerprint(public, fptype, rep);
ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
printf("%u %s %s (%s)\n", key_size(public), fp, name, printf("%u %s %s (%s)\n", key_size(public), fp, name,
key_type(public)); key_type(public));
if (log_level >= SYSLOG_LEVEL_VERBOSE) if (log_level >= SYSLOG_LEVEL_VERBOSE)
@ -629,7 +644,7 @@ print_host(FILE *f, const char *name, Key *public, int hash)
} else { } else {
if (hash && (name = host_hash(name, NULL, 0)) == NULL) if (hash && (name = host_hash(name, NULL, 0)) == NULL)
fatal("hash_host failed"); fatal("hash_host failed");
fprintf(f, "%s ", name); fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name);
if (!key_write(public, f)) if (!key_write(public, f))
fatal("key_write failed"); fatal("key_write failed");
fprintf(f, "\n"); fprintf(f, "\n");
@ -640,10 +655,11 @@ static void
do_known_hosts(struct passwd *pw, const char *name) do_known_hosts(struct passwd *pw, const char *name)
{ {
FILE *in, *out = stdout; FILE *in, *out = stdout;
Key *public; Key *pub;
char *cp, *cp2, *kp, *kp2; char *cp, *cp2, *kp, *kp2;
char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
int ca;
if (!have_identity) { if (!have_identity) {
cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
@ -699,9 +715,19 @@ do_known_hosts(struct passwd *pw, const char *name)
fprintf(out, "%s\n", cp); fprintf(out, "%s\n", cp);
continue; continue;
} }
/* Check whether this is a CA key */
if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 &&
(cp[sizeof(CA_MARKER) - 1] == ' ' ||
cp[sizeof(CA_MARKER) - 1] == '\t')) {
ca = 1;
cp += sizeof(CA_MARKER);
} else
ca = 0;
/* Find the end of the host name portion. */ /* Find the end of the host name portion. */
for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
; ;
if (*kp == '\0' || *(kp + 1) == '\0') { if (*kp == '\0' || *(kp + 1) == '\0') {
error("line %d missing key: %.40s...", error("line %d missing key: %.40s...",
num, line); num, line);
@ -711,15 +737,15 @@ do_known_hosts(struct passwd *pw, const char *name)
*kp++ = '\0'; *kp++ = '\0';
kp2 = kp; kp2 = kp;
public = key_new(KEY_RSA1); pub = key_new(KEY_RSA1);
if (key_read(public, &kp) != 1) { if (key_read(pub, &kp) != 1) {
kp = kp2; kp = kp2;
key_free(public); key_free(pub);
public = key_new(KEY_UNSPEC); pub = key_new(KEY_UNSPEC);
if (key_read(public, &kp) != 1) { if (key_read(pub, &kp) != 1) {
error("line %d invalid key: %.40s...", error("line %d invalid key: %.40s...",
num, line); num, line);
key_free(public); key_free(pub);
invalid = 1; invalid = 1;
continue; continue;
} }
@ -737,43 +763,52 @@ do_known_hosts(struct passwd *pw, const char *name)
c = (strcmp(cp2, cp) == 0); c = (strcmp(cp2, cp) == 0);
if (find_host && c) { if (find_host && c) {
printf("# Host %s found: " printf("# Host %s found: "
"line %d type %s\n", name, "line %d type %s%s\n", name,
num, key_type(public)); num, key_type(pub),
print_host(out, cp, public, 0); ca ? " (CA key)" : "");
printhost(out, cp, pub, ca, 0);
} }
if (delete_host && !c) if (delete_host && !c && !ca)
print_host(out, cp, public, 0); printhost(out, cp, pub, ca, 0);
} else if (hash_hosts) } else if (hash_hosts)
print_host(out, cp, public, 0); printhost(out, cp, pub, ca, 0);
} else { } else {
if (find_host || delete_host) { if (find_host || delete_host) {
c = (match_hostname(name, cp, c = (match_hostname(name, cp,
strlen(cp)) == 1); strlen(cp)) == 1);
if (find_host && c) { if (find_host && c) {
printf("# Host %s found: " printf("# Host %s found: "
"line %d type %s\n", name, "line %d type %s%s\n", name,
num, key_type(public)); num, key_type(pub),
print_host(out, name, public, ca ? " (CA key)" : "");
hash_hosts); printhost(out, name, pub,
ca, hash_hosts && !ca);
} }
if (delete_host && !c) if (delete_host && !c && !ca)
print_host(out, cp, public, 0); printhost(out, cp, pub, ca, 0);
} else if (hash_hosts) { } else if (hash_hosts) {
for (cp2 = strsep(&cp, ","); for (cp2 = strsep(&cp, ",");
cp2 != NULL && *cp2 != '\0'; cp2 != NULL && *cp2 != '\0';
cp2 = strsep(&cp, ",")) { cp2 = strsep(&cp, ",")) {
if (strcspn(cp2, "*?!") != strlen(cp2)) if (ca) {
fprintf(stderr, "Warning: "
"ignoring CA key for host: "
"%.64s\n", cp2);
printhost(out, cp2, pub, ca, 0);
} else if (strcspn(cp2, "*?!") !=
strlen(cp2)) {
fprintf(stderr, "Warning: " fprintf(stderr, "Warning: "
"ignoring host name with " "ignoring host name with "
"metacharacters: %.64s\n", "metacharacters: %.64s\n",
cp2); cp2);
else printhost(out, cp2, pub, ca, 0);
print_host(out, cp2, public, 1); } else
printhost(out, cp2, pub, ca, 1);
} }
has_unhashed = 1; has_unhashed = 1;
} }
} }
key_free(public); key_free(pub);
} }
fclose(in); fclose(in);
@ -1030,6 +1065,391 @@ do_change_comment(struct passwd *pw)
exit(0); exit(0);
} }
static const char *
fmt_validity(u_int64_t valid_from, u_int64_t valid_to)
{
char from[32], to[32];
static char ret[64];
time_t tt;
struct tm *tm;
*from = *to = '\0';
if (valid_from == 0 && valid_to == 0xffffffffffffffffULL)
return "forever";
if (valid_from != 0) {
/* XXX revisit INT_MAX in 2038 :) */
tt = valid_from > INT_MAX ? INT_MAX : valid_from;
tm = localtime(&tt);
strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
}
if (valid_to != 0xffffffffffffffffULL) {
/* XXX revisit INT_MAX in 2038 :) */
tt = valid_to > INT_MAX ? INT_MAX : valid_to;
tm = localtime(&tt);
strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
}
if (valid_from == 0) {
snprintf(ret, sizeof(ret), "before %s", to);
return ret;
}
if (valid_to == 0xffffffffffffffffULL) {
snprintf(ret, sizeof(ret), "after %s", from);
return ret;
}
snprintf(ret, sizeof(ret), "from %s to %s", from, to);
return ret;
}
static void
add_flag_constraint(Buffer *c, const char *name)
{
debug3("%s: %s", __func__, name);
buffer_put_cstring(c, name);
buffer_put_string(c, NULL, 0);
}
static void
add_string_constraint(Buffer *c, const char *name, const char *value)
{
Buffer b;
debug3("%s: %s=%s", __func__, name, value);
buffer_init(&b);
buffer_put_cstring(&b, value);
buffer_put_cstring(c, name);
buffer_put_string(c, buffer_ptr(&b), buffer_len(&b));
buffer_free(&b);
}
static void
prepare_constraint_buf(Buffer *c)
{
buffer_clear(c);
if ((constraint_flags & CONSTRAINT_X_FWD) != 0)
add_flag_constraint(c, "permit-X11-forwarding");
if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0)
add_flag_constraint(c, "permit-agent-forwarding");
if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0)
add_flag_constraint(c, "permit-port-forwarding");
if ((constraint_flags & CONSTRAINT_PTY) != 0)
add_flag_constraint(c, "permit-pty");
if ((constraint_flags & CONSTRAINT_USER_RC) != 0)
add_flag_constraint(c, "permit-user-rc");
if (constraint_command != NULL)
add_string_constraint(c, "force-command", constraint_command);
if (constraint_src_addr != NULL)
add_string_constraint(c, "source-address", constraint_src_addr);
}
static void
do_ca_sign(struct passwd *pw, int argc, char **argv)
{
int i, fd;
u_int n;
Key *ca, *public;
char *otmp, *tmp, *cp, *out, *comment, **plist = NULL;
FILE *f;
tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
if ((ca = load_identity(tmp)) == NULL)
fatal("Couldn't load CA key \"%s\"", tmp);
xfree(tmp);
for (i = 0; i < argc; i++) {
/* Split list of principals */
n = 0;
if (cert_principals != NULL) {
otmp = tmp = xstrdup(cert_principals);
plist = NULL;
for (; (cp = strsep(&tmp, ",")) != NULL; n++) {
plist = xrealloc(plist, n + 1, sizeof(*plist));
if (*(plist[n] = xstrdup(cp)) == '\0')
fatal("Empty principal name");
}
xfree(otmp);
}
tmp = tilde_expand_filename(argv[i], pw->pw_uid);
if ((public = key_load_public(tmp, &comment)) == NULL)
fatal("%s: unable to open \"%s\"", __func__, tmp);
if (public->type != KEY_RSA && public->type != KEY_DSA)
fatal("%s: key \"%s\" type %s cannot be certified",
__func__, tmp, key_type(public));
/* Prepare certificate to sign */
if (key_to_certified(public) != 0)
fatal("Could not upgrade key %s to certificate", tmp);
public->cert->type = cert_key_type;
public->cert->key_id = xstrdup(cert_key_id);
public->cert->nprincipals = n;
public->cert->principals = plist;
public->cert->valid_after = cert_valid_from;
public->cert->valid_before = cert_valid_to;
prepare_constraint_buf(&public->cert->constraints);
public->cert->signature_key = key_from_private(ca);
if (key_certify(public, ca) != 0)
fatal("Couldn't not certify key %s", tmp);
if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
*cp = '\0';
xasprintf(&out, "%s-cert.pub", tmp);
xfree(tmp);
if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
fatal("Could not open \"%s\" for writing: %s", out,
strerror(errno));
if ((f = fdopen(fd, "w")) == NULL)
fatal("%s: fdopen: %s", __func__, strerror(errno));
if (!key_write(public, f))
fatal("Could not write certified key to %s", out);
fprintf(f, " %s\n", comment);
fclose(f);
if (!quiet)
logit("Signed %s key %s: id \"%s\"%s%s valid %s",
cert_key_type == SSH2_CERT_TYPE_USER?"user":"host",
out, cert_key_id,
cert_principals != NULL ? " for " : "",
cert_principals != NULL ? cert_principals : "",
fmt_validity(cert_valid_from, cert_valid_to));
key_free(public);
xfree(out);
}
exit(0);
}
static u_int64_t
parse_relative_time(const char *s, time_t now)
{
int64_t mul, secs;
mul = *s == '-' ? -1 : 1;
if ((secs = convtime(s + 1)) == -1)
fatal("Invalid relative certificate time %s", s);
if (mul == -1 && secs > now)
fatal("Certificate time %s cannot be represented", s);
return now + (u_int64_t)(secs * mul);
}
static u_int64_t
parse_absolute_time(const char *s)
{
struct tm tm;
time_t tt;
char buf[32], *fmt;
/*
* POSIX strptime says "The application shall ensure that there
* is white-space or other non-alphanumeric characters between
* any two conversion specifications" so arrange things this way.
*/
switch (strlen(s)) {
case 8:
fmt = "%Y-%m-%d";
snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
break;
case 14:
fmt = "%Y-%m-%dT%H:%M:%S";
snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
s, s + 4, s + 6, s + 8, s + 10, s + 12);
break;
default:
fatal("Invalid certificate time format %s", s);
}
bzero(&tm, sizeof(tm));
if (strptime(buf, fmt, &tm) == NULL)
fatal("Invalid certificate time %s", s);
if ((tt = mktime(&tm)) < 0)
fatal("Certificate time %s cannot be represented", s);
return (u_int64_t)tt;
}
static void
parse_cert_times(char *timespec)
{
char *from, *to;
time_t now = time(NULL);
int64_t secs;
/* +timespec relative to now */
if (*timespec == '+' && strchr(timespec, ':') == NULL) {
if ((secs = convtime(timespec + 1)) == -1)
fatal("Invalid relative certificate life %s", timespec);
cert_valid_to = now + secs;
/*
* Backdate certificate one minute to avoid problems on hosts
* with poorly-synchronised clocks.
*/
cert_valid_from = ((now - 59)/ 60) * 60;
return;
}
/*
* from:to, where
* from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
* to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
*/
from = xstrdup(timespec);
to = strchr(from, ':');
if (to == NULL || from == to || *(to + 1) == '\0')
fatal("Invalid certificate life specification %s", timespec);
*to++ = '\0';
if (*from == '-' || *from == '+')
cert_valid_from = parse_relative_time(from, now);
else
cert_valid_from = parse_absolute_time(from);
if (*to == '-' || *to == '+')
cert_valid_to = parse_relative_time(to, cert_valid_from);
else
cert_valid_to = parse_absolute_time(to);
if (cert_valid_to <= cert_valid_from)
fatal("Empty certificate validity interval");
xfree(from);
}
static void
add_cert_constraint(char *opt)
{
char *val;
if (strcmp(opt, "clear") == 0)
constraint_flags = 0;
else if (strcasecmp(opt, "no-x11-forwarding") == 0)
constraint_flags &= ~CONSTRAINT_X_FWD;
else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
constraint_flags |= CONSTRAINT_X_FWD;
else if (strcasecmp(opt, "no-agent-forwarding") == 0)
constraint_flags &= ~CONSTRAINT_AGENT_FWD;
else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
constraint_flags |= CONSTRAINT_AGENT_FWD;
else if (strcasecmp(opt, "no-port-forwarding") == 0)
constraint_flags &= ~CONSTRAINT_PORT_FWD;
else if (strcasecmp(opt, "permit-port-forwarding") == 0)
constraint_flags |= CONSTRAINT_PORT_FWD;
else if (strcasecmp(opt, "no-pty") == 0)
constraint_flags &= ~CONSTRAINT_PTY;
else if (strcasecmp(opt, "permit-pty") == 0)
constraint_flags |= CONSTRAINT_PTY;
else if (strcasecmp(opt, "no-user-rc") == 0)
constraint_flags &= ~CONSTRAINT_USER_RC;
else if (strcasecmp(opt, "permit-user-rc") == 0)
constraint_flags |= CONSTRAINT_USER_RC;
else if (strncasecmp(opt, "force-command=", 14) == 0) {
val = opt + 14;
if (*val == '\0')
fatal("Empty force-command constraint");
if (constraint_command != NULL)
fatal("force-command already specified");
constraint_command = xstrdup(val);
} else if (strncasecmp(opt, "source-address=", 15) == 0) {
val = opt + 15;
if (*val == '\0')
fatal("Empty source-address constraint");
if (constraint_src_addr != NULL)
fatal("source-address already specified");
if (addr_match_cidr_list(NULL, val) != 0)
fatal("Invalid source-address list");
constraint_src_addr = xstrdup(val);
} else
fatal("Unsupported certificate constraint \"%s\"", opt);
}
static void
do_show_cert(struct passwd *pw)
{
Key *key;
struct stat st;
char *key_fp, *ca_fp;
Buffer constraints, constraint;
u_char *name, *data;
u_int i, dlen;
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 ((key = key_load_public(identity_file, NULL)) == NULL)
fatal("%s is not a public key", identity_file);
if (!key_is_cert(key))
fatal("%s is not a certificate", identity_file);
key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
ca_fp = key_fingerprint(key->cert->signature_key,
SSH_FP_MD5, SSH_FP_HEX);
printf("%s:\n", identity_file);
printf(" %s certificate %s\n", key_type(key), key_fp);
printf(" Signed by %s CA %s\n",
key_type(key->cert->signature_key), ca_fp);
printf(" Key ID \"%s\"\n", key->cert->key_id);
printf(" Valid: %s\n",
fmt_validity(key->cert->valid_after, key->cert->valid_before));
printf(" Principals: ");
if (key->cert->nprincipals == 0)
printf("(none)\n");
else {
for (i = 0; i < key->cert->nprincipals; i++)
printf("\n %s",
key->cert->principals[i]);
printf("\n");
}
printf(" Constraints: ");
if (buffer_len(&key->cert->constraints) == 0)
printf("(none)\n");
else {
printf("\n");
buffer_init(&constraints);
buffer_append(&constraints,
buffer_ptr(&key->cert->constraints),
buffer_len(&key->cert->constraints));
buffer_init(&constraint);
while (buffer_len(&constraints) != 0) {
name = buffer_get_string(&constraints, NULL);
data = buffer_get_string_ptr(&constraints, &dlen);
buffer_append(&constraint, data, dlen);
printf(" %s", name);
if (strcmp(name, "permit-X11-forwarding") == 0 ||
strcmp(name, "permit-agent-forwarding") == 0 ||
strcmp(name, "permit-port-forwarding") == 0 ||
strcmp(name, "permit-pty") == 0 ||
strcmp(name, "permit-user-rc") == 0)
printf("\n");
else if (strcmp(name, "force-command") == 0 ||
strcmp(name, "source-address") == 0) {
data = buffer_get_string(&constraint, NULL);
printf(" %s\n", data);
xfree(data);
} else {
printf(" UNKNOWN CONSTRAINT (len %u)\n",
buffer_len(&constraint));
buffer_clear(&constraint);
}
xfree(name);
if (buffer_len(&constraint) != 0)
fatal("Constraint corrupt: extra data at end");
}
buffer_free(&constraint);
buffer_free(&constraints);
}
exit(0);
}
static void static void
usage(void) usage(void)
{ {
@ -1040,30 +1460,34 @@ usage(void)
fprintf(stderr, " -b bits Number of bits in the key to create.\n"); fprintf(stderr, " -b bits Number of bits in the key to create.\n");
fprintf(stderr, " -C comment Provide new comment.\n"); fprintf(stderr, " -C comment Provide new comment.\n");
fprintf(stderr, " -c Change comment in private and public key files.\n"); fprintf(stderr, " -c Change comment in private and public key files.\n");
#ifdef SMARTCARD #ifdef ENABLE_PKCS11
fprintf(stderr, " -D reader Download public key from smartcard.\n"); fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n");
#endif /* SMARTCARD */ #endif
fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n");
fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); fprintf(stderr, " -F hostname Find hostname in known hosts file.\n");
fprintf(stderr, " -f filename Filename of the key file.\n"); fprintf(stderr, " -f filename Filename of the key file.\n");
fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n");
fprintf(stderr, " -g Use generic DNS resource record format.\n"); fprintf(stderr, " -g Use generic DNS resource record format.\n");
fprintf(stderr, " -H Hash names in known_hosts file.\n"); fprintf(stderr, " -H Hash names in known_hosts file.\n");
fprintf(stderr, " -h Generate host certificate instead of a user certificate.\n");
fprintf(stderr, " -I key_id Key identifier to include in certificate.\n");
fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n");
fprintf(stderr, " -L Print the contents of a certificate.\n");
fprintf(stderr, " -l Show fingerprint of key file.\n"); fprintf(stderr, " -l Show fingerprint of key file.\n");
fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n");
fprintf(stderr, " -n name,... User/host principal names to include in certificate\n");
fprintf(stderr, " -N phrase Provide new passphrase.\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n");
fprintf(stderr, " -O cnstr Specify a certificate constraint.\n");
fprintf(stderr, " -P phrase Provide old passphrase.\n"); fprintf(stderr, " -P phrase Provide old passphrase.\n");
fprintf(stderr, " -p Change passphrase of private key file.\n"); fprintf(stderr, " -p Change passphrase of private key file.\n");
fprintf(stderr, " -q Quiet.\n"); fprintf(stderr, " -q Quiet.\n");
fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); fprintf(stderr, " -R hostname Remove host from known_hosts file.\n");
fprintf(stderr, " -r hostname Print DNS resource record.\n"); fprintf(stderr, " -r hostname Print DNS resource record.\n");
fprintf(stderr, " -s ca_key Certify keys with CA key.\n");
fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n");
fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n");
fprintf(stderr, " -t type Specify type of key to create.\n"); fprintf(stderr, " -t type Specify type of key to create.\n");
#ifdef SMARTCARD fprintf(stderr, " -V from:to Specify certificate validity interval.\n");
fprintf(stderr, " -U reader Upload private key to smartcard.\n");
#endif /* SMARTCARD */
fprintf(stderr, " -v Verbose.\n"); fprintf(stderr, " -v Verbose.\n");
fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n");
fprintf(stderr, " -y Read private key file and print public key.\n"); fprintf(stderr, " -y Read private key file and print public key.\n");
@ -1078,12 +1502,12 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
char out_file[MAXPATHLEN], *reader_id = NULL; char out_file[MAXPATHLEN], *pkcs11provider = NULL;
char *rr_hostname = NULL; char *rr_hostname = NULL;
Key *private, *public; Key *private, *public;
struct passwd *pw; struct passwd *pw;
struct stat st; struct stat st;
int opt, type, fd, download = 0; int opt, type, fd;
u_int32_t memory = 0, generator_wanted = 0, trials = 100; u_int32_t memory = 0, generator_wanted = 0, trials = 100;
int do_gen_candidates = 0, do_screen_candidates = 0; int do_gen_candidates = 0, do_screen_candidates = 0;
BIGNUM *start = NULL; BIGNUM *start = NULL;
@ -1115,8 +1539,8 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
while ((opt = getopt(argc, argv, while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:"
"degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) {
switch (opt) { switch (opt) {
case 'b': case 'b':
bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
@ -1131,16 +1555,25 @@ main(int argc, char **argv)
case 'H': case 'H':
hash_hosts = 1; hash_hosts = 1;
break; break;
case 'I':
cert_key_id = optarg;
break;
case 'R': case 'R':
delete_host = 1; delete_host = 1;
rr_hostname = optarg; rr_hostname = optarg;
break; break;
case 'L':
show_cert = 1;
break;
case 'l': case 'l':
print_fingerprint = 1; print_fingerprint = 1;
break; break;
case 'B': case 'B':
print_bubblebabble = 1; print_bubblebabble = 1;
break; break;
case 'n':
cert_principals = optarg;
break;
case 'p': case 'p':
change_passphrase = 1; change_passphrase = 1;
break; break;
@ -1162,6 +1595,9 @@ main(int argc, char **argv)
case 'N': case 'N':
identity_new_passphrase = optarg; identity_new_passphrase = optarg;
break; break;
case 'O':
add_cert_constraint(optarg);
break;
case 'C': case 'C':
identity_comment = optarg; identity_comment = optarg;
break; break;
@ -1173,6 +1609,10 @@ main(int argc, char **argv)
/* export key */ /* export key */
convert_to_ssh2 = 1; convert_to_ssh2 = 1;
break; break;
case 'h':
cert_key_type = SSH2_CERT_TYPE_HOST;
constraint_flags = 0;
break;
case 'i': case 'i':
case 'X': case 'X':
/* import key */ /* import key */
@ -1184,14 +1624,14 @@ main(int argc, char **argv)
case 'd': case 'd':
key_type_name = "dsa"; key_type_name = "dsa";
break; break;
case 's':
ca_key_path = optarg;
break;
case 't': case 't':
key_type_name = optarg; key_type_name = optarg;
break; break;
case 'D': case 'D':
download = 1; pkcs11provider = optarg;
/*FALLTHROUGH*/
case 'U':
reader_id = optarg;
break; break;
case 'v': case 'v':
if (log_level == SYSLOG_LEVEL_INFO) if (log_level == SYSLOG_LEVEL_INFO)
@ -1241,6 +1681,9 @@ main(int argc, char **argv)
if (BN_hex2bn(&start, optarg) == 0) if (BN_hex2bn(&start, optarg) == 0)
fatal("Invalid start point."); fatal("Invalid start point.");
break; break;
case 'V':
parse_cert_times(optarg);
break;
case '?': case '?':
default: default:
usage(); usage();
@ -1250,7 +1693,15 @@ main(int argc, char **argv)
/* reinit */ /* reinit */
log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
if (optind < argc) { argv += optind;
argc -= optind;
if (ca_key_path != NULL) {
if (argc < 1) {
printf("Too few arguments.\n");
usage();
}
} else if (argc > 0) {
printf("Too many arguments.\n"); printf("Too many arguments.\n");
usage(); usage();
} }
@ -1262,6 +1713,13 @@ main(int argc, char **argv)
printf("Cannot use -l with -D or -R.\n"); printf("Cannot use -l with -D or -R.\n");
usage(); usage();
} }
if (ca_key_path != NULL) {
if (cert_key_id == NULL)
fatal("Must specify key id (-I) when certifying");
do_ca_sign(pw, argc, argv);
}
if (show_cert)
do_show_cert(pw);
if (delete_host || hash_hosts || find_host) if (delete_host || hash_hosts || find_host)
do_known_hosts(pw, rr_hostname); do_known_hosts(pw, rr_hostname);
if (print_fingerprint || print_bubblebabble) if (print_fingerprint || print_bubblebabble)
@ -1299,16 +1757,8 @@ main(int argc, char **argv)
exit(0); exit(0);
} }
} }
if (reader_id != NULL) { if (pkcs11provider != NULL)
#ifdef SMARTCARD do_download(pw, pkcs11provider);
if (download)
do_download(pw, reader_id);
else
do_upload(pw, reader_id);
#else /* SMARTCARD */
fatal("no support for smartcards.");
#endif /* SMARTCARD */
}
if (do_gen_candidates) { if (do_gen_candidates) {
FILE *out = fopen(out_file, "w"); FILE *out = fopen(out_file, "w");

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keyscan.1,v 1.26 2008/12/29 01:12:36 stevesk Exp $ .\" $OpenBSD: ssh-keyscan.1,v 1.28 2010/01/09 23:04:13 dtucker Exp $
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. .\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
@ -7,7 +7,7 @@
.\" permitted provided that due credit is given to the author and the .\" permitted provided that due credit is given to the author and the
.\" OpenBSD project by leaving this copyright notice intact. .\" OpenBSD project by leaving this copyright notice intact.
.\" .\"
.Dd December 29 2008 .Dd January 9 2010
.Dt SSH-KEYSCAN 1 .Dt SSH-KEYSCAN 1
.Os .Os
.Sh NAME .Sh NAME

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keyscan.c,v 1.78 2009/01/22 10:02:34 djm Exp $ */ /* $OpenBSD: ssh-keyscan.c,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */
/* /*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
* *

Some files were not shown because too many files have changed in this diff Show More