diff options
author | Damien Miller <djm@mindrot.org> | 2000-09-05 13:34:53 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2000-09-05 13:34:53 +1100 |
commit | 7b28dc5eb0b4d766ddbf5c1955de7e4edbe50e7c (patch) | |
tree | a3f8409e421134c543a49851c5cfd9d62a0455d5 | |
parent | 123cbe8e86b1f6e4c4dc016e76dcac1616971089 (diff) |
- (djm) Import OpenBSD CVS changes
- markus@cvs.openbsd.org 2000/08/31 15:52:24
[Makefile sshd.8 sshd_config sftp-server.8 sftp-server.c]
implement a SFTP server. interops with sftp2, scp2 and the windows
client from ssh.com
- markus@cvs.openbsd.org 2000/08/31 15:56:03
[README.openssh2]
sync
- markus@cvs.openbsd.org 2000/08/31 16:05:42
[session.c]
Wall
- markus@cvs.openbsd.org 2000/08/31 16:09:34
[authfd.c ssh-agent.c]
add a flag to SSH2_AGENTC_SIGN_REQUEST for future extensions
- deraadt@cvs.openbsd.org 2000/09/01 09:25:13
[scp.1 scp.c]
cleanup and fix -S support; stevesk@sweden.hp.com
- markus@cvs.openbsd.org 2000/09/01 16:29:32
[sftp-server.c]
portability fixes
- markus@cvs.openbsd.org 2000/09/01 16:32:41
[sftp-server.c]
fix cast; mouring@pconline.com
- itojun@cvs.openbsd.org 2000/09/03 09:23:28
[ssh-add.1 ssh.1]
add missing .El against .Bl.
- markus@cvs.openbsd.org 2000/09/04 13:03:41
[session.c]
missing close; ok theo
- markus@cvs.openbsd.org 2000/09/04 13:07:21
[session.c]
fix get_last_login_time order; from andre@van-veen.de
- markus@cvs.openbsd.org 2000/09/04 13:10:09
[sftp-server.c]
more cast fixes; from mouring@pconline.com
- markus@cvs.openbsd.org 2000/09/04 13:06:04
[session.c]
set SSH_ORIGINAL_COMMAND; from Leakin@dfw.nostrum.com, bet@rahul.net
- (djm) Cleanup after import. Fix sftp-server compilation, Makefile
-rw-r--r-- | ChangeLog | 40 | ||||
-rw-r--r-- | Makefile.in | 18 | ||||
-rw-r--r-- | README.openssh2 | 17 | ||||
-rw-r--r-- | authfd.c | 3 | ||||
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | scp.1 | 15 | ||||
-rw-r--r-- | scp.c | 4 | ||||
-rw-r--r-- | session.c | 35 | ||||
-rw-r--r-- | sftp-server.8 | 33 | ||||
-rw-r--r-- | sftp-server.c | 1078 | ||||
-rw-r--r-- | ssh-add.1 | 5 | ||||
-rw-r--r-- | ssh-agent.c | 5 | ||||
-rw-r--r-- | ssh.1 | 4 | ||||
-rw-r--r-- | sshd.8 | 8 | ||||
-rw-r--r-- | sshd_config | 3 |
15 files changed, 1222 insertions, 48 deletions
@@ -1,3 +1,43 @@ +20000905 + - (djm) Import OpenBSD CVS changes + - markus@cvs.openbsd.org 2000/08/31 15:52:24 + [Makefile sshd.8 sshd_config sftp-server.8 sftp-server.c] + implement a SFTP server. interops with sftp2, scp2 and the windows + client from ssh.com + - markus@cvs.openbsd.org 2000/08/31 15:56:03 + [README.openssh2] + sync + - markus@cvs.openbsd.org 2000/08/31 16:05:42 + [session.c] + Wall + - markus@cvs.openbsd.org 2000/08/31 16:09:34 + [authfd.c ssh-agent.c] + add a flag to SSH2_AGENTC_SIGN_REQUEST for future extensions + - deraadt@cvs.openbsd.org 2000/09/01 09:25:13 + [scp.1 scp.c] + cleanup and fix -S support; stevesk@sweden.hp.com + - markus@cvs.openbsd.org 2000/09/01 16:29:32 + [sftp-server.c] + portability fixes + - markus@cvs.openbsd.org 2000/09/01 16:32:41 + [sftp-server.c] + fix cast; mouring@pconline.com + - itojun@cvs.openbsd.org 2000/09/03 09:23:28 + [ssh-add.1 ssh.1] + add missing .El against .Bl. + - markus@cvs.openbsd.org 2000/09/04 13:03:41 + [session.c] + missing close; ok theo + - markus@cvs.openbsd.org 2000/09/04 13:07:21 + [session.c] + fix get_last_login_time order; from andre@van-veen.de + - markus@cvs.openbsd.org 2000/09/04 13:10:09 + [sftp-server.c] + more cast fixes; from mouring@pconline.com + - markus@cvs.openbsd.org 2000/09/04 13:06:04 + [session.c] + set SSH_ORIGINAL_COMMAND; from Leakin@dfw.nostrum.com, bet@rahul.net + - (djm) Cleanup after import. Fix sftp-server compilation, Makefile 20000903 - (djm) Fix Redhat init script diff --git a/Makefile.in b/Makefile.in index 4ceef704..7eb84ce6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -15,8 +15,8 @@ DESTDIR= VPATH=@srcdir@ SSH_PROGRAM=@bindir@/ssh -ASKPASS_LOCATION=@libexecdir@/ssh -ASKPASS_PROGRAM=$(ASKPASS_LOCATION)/ssh-askpass +LIBEXEC=@libexecdir@/ssh +ASKPASS_PROGRAM=$(LIBEXEC)/ssh-askpass CC=@CC@ LD=@LD@ @@ -32,7 +32,7 @@ LDFLAGS=-L. @LDFLAGS@ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ -TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) +TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp sftp-server $(EXTRA_TARGETS) LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o util.o uuencode.o xmalloc.o @@ -42,13 +42,13 @@ SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o log-client.o readconf.o SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth-rhosts.o auth-options.o auth-krb4.o auth-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o log-server.o login.o loginrec.o servconf.o serverloop.o md5crypt.o session.o -TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 -CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 +TROFFMAN = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh.1 sshd.8 sftp-server.8 +CATMAN = scp.0 ssh-add.0 ssh-agent.0 ssh-keygen.0 ssh.0 sshd.0 sftp-server.0 MANPAGES = @MANTYPE@ CONFIGFILES=sshd_config ssh_config -PATHSUBS = -D/etc/ssh_config=$(sysconfdir)/ssh_config -D/etc/known_hosts=$(sysconfdir)/ssh_known_hosts -D/etc/sshd_config=$(sysconfdir)/sshd_config -D/etc/shosts.equiv=$(sysconfdir)/shosts.equiv -D/etc/ssh_host_key=$(sysconfdir)/ssh_host_key -D/var/run/sshd.pid=$(piddir)/sshd.pid +PATHSUBS = -D/etc/ssh_config=$(sysconfdir)/ssh_config -D/etc/known_hosts=$(sysconfdir)/ssh_known_hosts -D/etc/sshd_config=$(sysconfdir)/sshd_config -D/usr/libexec=$(LIBEXEC) -D/etc/shosts.equiv=$(sysconfdir)/shosts.equiv -D/etc/ssh_host_key=$(sysconfdir)/ssh_host_key -D/var/run/sshd.pid=$(piddir)/sshd.pid FIXPATHSCMD = $(PERL) $(srcdir)/fixpaths $(PATHSUBS) @@ -86,6 +86,9 @@ ssh-agent: libopenbsd-compat.a libssh.a ssh-agent.o log-client.o ssh-keygen: libopenbsd-compat.a libssh.a ssh-keygen.o log-client.o $(LD) -o $@ ssh-keygen.o log-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +sftp-server: libopenbsd-compat.a libssh.a sftp-server.o log-server.o + $(LD) -o $@ sftp-server.o log-server.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + # test driver for the loginrec code - not built by default logintest: logintest.o libopenbsd-compat.a libssh.a log-client.o loginrec.o $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh log-client.o $(LIBS) @@ -123,18 +126,21 @@ install-files: ./mkinstalldirs $(DESTDIR)$(mandir) ./mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)1 ./mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)8 + ./mkinstalldirs $(DESTDIR)$(LIBEXEC) $(INSTALL) -m 4755 -s ssh $(DESTDIR)$(bindir)/ssh $(INSTALL) -m 0755 -s scp $(DESTDIR)$(bindir)/scp $(INSTALL) -m 0755 -s ssh-add $(DESTDIR)$(bindir)/ssh-add $(INSTALL) -m 0755 -s ssh-agent $(DESTDIR)$(bindir)/ssh-agent $(INSTALL) -m 0755 -s ssh-keygen $(DESTDIR)$(bindir)/ssh-keygen $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd + $(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(LIBEXEC)/sftp-server $(INSTALL) -m 644 ssh.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 $(INSTALL) -m 644 scp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 $(INSTALL) -m 644 ssh-add.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 $(INSTALL) -m 644 ssh-agent.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 $(INSTALL) -m 644 ssh-keygen.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 $(INSTALL) -m 644 sshd.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 + $(INSTALL) -m 644 sftp-server.[08].out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 -rm -f $(DESTDIR)$(bindir)/slogin ln -s ssh $(DESTDIR)$(bindir)/slogin -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 diff --git a/README.openssh2 b/README.openssh2 index 12c90aa3..df737c69 100644 --- a/README.openssh2 +++ b/README.openssh2 @@ -1,4 +1,4 @@ -$Id: README.openssh2,v 1.8 2000/05/07 18:30:03 markus Exp $ +$Id: README.openssh2,v 1.9 2000/08/31 21:56:03 markus Exp $ howto: 1) generate server key: @@ -15,30 +15,27 @@ howto: works: secsh-transport: works w/o rekey - proposal exchange, i.e. different enc/mac/comp per direction - encryption: blowfish-cbc, 3des-cbc, arcfour, cast128-cbc - mac: hmac-md5, hmac-sha1, (hmac-ripemd160) - compression: zlib, none secsh-userauth: passwd and pubkey with DSA secsh-connection: pty+shell or command, flow control works (window adjust) tcp-forwarding: -L works, -R incomplete x11-fwd dss/dsa: host key database in ~/.ssh/known_hosts2 + ssh-agent: supports SSH1-RSA and ssh-dss keys client interops w/ sshd2, lshd server interops w/ ssh2, lsh, ssh.com's Windows client, SecureCRT, F-Secure SSH Client 4.0, SecureFX (secure ftp) server supports multiple concurrent sessions (e.g. with SSH.com Windows client) + server supports SFTP (interops with ssh.com's windows, sftp2, scp2) todo: - re-keying + RE-KEYING secsh-connection features: - tcp-forwarding, agent-fwd + complete tcp-forwarding, agent-fwd auth other than passwd, and DSA-pubkey: - keyboard-interactive, (PGP-pubkey?) + keyboard-interactive, (PGP-pubkey?), kerberos config server-auth w/ old host-keys cleanup advanced key storage? keynote - sftp -markus -$Date: 2000/05/07 18:30:03 $ +$Date: 2000/08/31 21:56:03 $ @@ -17,7 +17,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: authfd.c,v 1.25 2000/08/19 21:34:42 markus Exp $"); +RCSID("$OpenBSD: authfd.c,v 1.26 2000/08/31 22:09:34 markus Exp $"); #include "ssh.h" #include "rsa.h" @@ -359,6 +359,7 @@ ssh_agent_sign(AuthenticationConnection *auth, buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, data, datalen); + buffer_put_int(&msg, 0); /* flags, unused */ xfree(blob); if (ssh_request_reply(auth, &msg, &msg) == 0) { diff --git a/configure.in b/configure.in index 33b82895..b1dd1d06 100644 --- a/configure.in +++ b/configure.in @@ -235,7 +235,7 @@ fi AC_CHECK_HEADERS(bstring.h endian.h floatingpoint.h lastlog.h limits.h login.h login_cap.h maillock.h netdb.h netgroup.h netinet/in_systm.h paths.h poll.h pty.h shadow.h security/pam_appl.h sys/bitypes.h sys/bsdtty.h sys/cdefs.h sys/poll.h sys/select.h sys/stat.h sys/stropts.h sys/sysmacros.h sys/time.h sys/ttcompat.h stddef.h time.h ttyent.h usersec.h util.h utmp.h utmpx.h) dnl Checks for library functions. -AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_af clock freeaddrinfo gai_strerror getaddrinfo getnameinfo getrusage getttyent inet_aton inet_ntoa innetgr login_getcapbool md5_crypt memmove mkdtemp on_exit openpty rresvport_af setenv seteuid setlogin setproctitle setreuid sigaction sigvec snprintf strerror strlcat strlcpy strsep vsnprintf vhangup _getpty __b64_ntop) +AC_CHECK_FUNCS(arc4random atexit b64_ntop bcopy bindresvport_af clock freeaddrinfo futimes gai_strerror getaddrinfo getnameinfo getrusage getttyent inet_aton inet_ntoa innetgr login_getcapbool md5_crypt memmove mkdtemp on_exit openpty rresvport_af setenv seteuid setlogin setproctitle setreuid sigaction sigvec snprintf strerror strlcat strlcpy strsep vsnprintf vhangup _getpty __b64_ntop) dnl Checks for time functions AC_CHECK_FUNCS(gettimeofday time) dnl Checks for libutil functions @@ -9,7 +9,7 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $Id: scp.1,v 1.9 2000/08/23 00:46:24 djm Exp $ +.\" $Id: scp.1,v 1.10 2000/09/05 02:34:54 djm Exp $ .\" .Dd September 25, 1999 .Dt SCP 1 @@ -20,6 +20,7 @@ .Sh SYNOPSIS .Nm scp .Op Fl pqrvC46 +.Op Fl S Ar program .Op Fl P Ar port .Op Fl c Ar cipher .Op Fl i Ar identity_file @@ -68,11 +69,6 @@ This option is directly passed to .It Fl p Preserves modification times, access times, and modes from the original file. -.It Fl S -Name of program to use for the encrypted connection. -The program must understand -.Xr ssh 1 -options. .It Fl r Recursively copy entire directories. .It Fl v @@ -103,9 +99,10 @@ because .Fl p is already reserved for preserving the times and modes of the file in .Xr rcp 1 . -.It Fl S -Name of program to use for the encrypted connection. The program must -understand +.It Fl S Ar program +Name of +.Ar program +to use for the encrypted connection. The program must understand .Xr ssh 1 options. .It Fl 4 @@ -47,7 +47,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: scp.c,v 1.36 2000/08/24 21:46:59 deraadt Exp $"); +RCSID("$OpenBSD: scp.c,v 1.37 2000/09/01 15:25:13 deraadt Exp $"); #include "ssh.h" #include "xmalloc.h" @@ -262,7 +262,7 @@ main(argc, argv) extern int optind; fflag = tflag = 0; - while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S")) != EOF) + while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:")) != EOF) switch (ch) { /* User-visible flags. */ case '4': @@ -8,7 +8,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: session.c,v 1.31 2000/08/28 03:50:54 deraadt Exp $"); +RCSID("$OpenBSD: session.c,v 1.35 2000/09/04 19:07:21 markus Exp $"); #include "xmalloc.h" #include "ssh.h" @@ -113,6 +113,9 @@ extern int startup_pipe; /* Local Xauthority file. */ static char *xauthfile; +/* original command from peer. */ +char *original_command = NULL; + /* data */ #define MAX_SESSIONS 10 Session sessions[MAX_SESSIONS]; @@ -177,7 +180,7 @@ void do_authenticated(struct passwd * pw) { Session *s; - int type; + int type, fd; int compression_level = 0, enable_compression_after_reply = 0; int have_pty = 0; char *command; @@ -332,7 +335,9 @@ do_authenticated(struct passwd * pw) break; } strlcat(xauthfile, "/cookies", MAXPATHLEN); - open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); + fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd >= 0) + close(fd); restore_uid(); fatal_add_cleanup(xauthfile_cleanup_proc, NULL); success = 1; @@ -377,6 +382,7 @@ do_authenticated(struct passwd * pw) packet_integrity_check(plen, 0, type); } if (forced_command != NULL) { + original_command = command; command = forced_command; debug("Forced command '%.500s'", forced_command); } @@ -638,6 +644,7 @@ do_login(Session *s) FILE *f; char *time_string; char buf[256]; + char hostname[MAXHOSTNAMELEN]; socklen_t fromlen; struct sockaddr_storage from; struct stat st; @@ -659,6 +666,10 @@ do_login(Session *s) } } + /* Get the time and hostname when the user last logged in. */ + last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, + hostname, sizeof(hostname)); + /* Record that there was a login on that tty from the remote host. */ record_login(pid, s->tty, pw->pw_name, pw->pw_uid, get_remote_name_or_ip(), (struct sockaddr *)&from); @@ -680,12 +691,6 @@ do_login(Session *s) printf("%s\n", aixloginmsg); #endif /* WITH_AIXAUTHENTICATE */ - /* - * Get the time when the user last logged in. 'buf' will be set - * to contain the hostname the last login was from. - */ - last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, - buf, sizeof(buf)); if (last_login_time != 0) { time_string = ctime(&last_login_time); if (strchr(time_string, '\n')) @@ -911,7 +916,7 @@ do_child(const char *command, struct passwd * pw, const char *term, const char *display, const char *auth_proto, const char *auth_data, const char *ttyname) { - const char *shell, *hostname, *cp = NULL; + const char *shell, *hostname = NULL, *cp = NULL; char buf[256]; char cmd[1024]; FILE *f = NULL; @@ -1089,6 +1094,9 @@ do_child(const char *command, struct passwd * pw, const char *term, child_set_env(&env, &envsize, "TERM", term); if (display) child_set_env(&env, &envsize, "DISPLAY", display); + if (original_command) + child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", + original_command); #ifdef _AIX { @@ -1511,6 +1519,7 @@ session_subsystem_req(Session *s) int session_x11_req(Session *s) { + int fd; if (no_x11_forwarding_flag) { debug("X11 forwarding disabled in user configuration file."); return 0; @@ -1555,7 +1564,9 @@ session_x11_req(Session *s) return 0; } strlcat(xauthfile, "/cookies", MAXPATHLEN); - open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); + fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd >= 0) + close(fd); restore_uid(); fatal_add_cleanup(xauthfile_cleanup_proc, s); return 1; @@ -1582,7 +1593,7 @@ session_exec_req(Session *s) char *command = packet_get_string(&len); packet_done(); if (forced_command) { - xfree(command); + original_command = command; command = forced_command; debug("Forced command '%.500s'", forced_command); } diff --git a/sftp-server.8 b/sftp-server.8 new file mode 100644 index 00000000..85720a08 --- /dev/null +++ b/sftp-server.8 @@ -0,0 +1,33 @@ +.\" $OpenBSD: sftp-server.8,v 1.1 2000/08/31 21:52:23 markus Exp $ +.Dd August 30, 2000 +.Dt SFTP-SERVER 8 +.Os +.Sh NAME +.Nm sftp-server +.Nd SFTP server subsystem +.Sh SYNOPSIS +.Nm sftp-server +.Sh DESCRIPTION +.Nm +is a program that speaks the server side of SFTP protocol +to stdout and expects client requests from stdin. +.Nm +is not intended to be called directly, but from +.Xr sshd 8 +using the +.Cm Subsystem +option. +See +.Xr sshd 8 +for more information. +.Sh HISTORY +.Nm +first appeared in +.Ox 2.8 . +.Sh AUTHOR +Markus Friedl <markus@openbsd.org> +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-keygen 1 , +.Xr sshd 8 , diff --git a/sftp-server.c b/sftp-server.c new file mode 100644 index 00000000..39cecac5 --- /dev/null +++ b/sftp-server.c @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Markus Friedl. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: sftp-server.c,v 1.4 2000/09/04 19:10:08 markus Exp $"); + +#include "ssh.h" +#include "buffer.h" +#include "bufaux.h" +#include "getput.h" +#include "xmalloc.h" + +/* version */ +#define SSH_FILEXFER_VERSION 2 + +/* client to server */ +#define SSH_FXP_INIT 1 +#define SSH_FXP_OPEN 3 +#define SSH_FXP_CLOSE 4 +#define SSH_FXP_READ 5 +#define SSH_FXP_WRITE 6 +#define SSH_FXP_LSTAT 7 +#define SSH_FXP_FSTAT 8 +#define SSH_FXP_SETSTAT 9 +#define SSH_FXP_FSETSTAT 10 +#define SSH_FXP_OPENDIR 11 +#define SSH_FXP_READDIR 12 +#define SSH_FXP_REMOVE 13 +#define SSH_FXP_MKDIR 14 +#define SSH_FXP_RMDIR 15 +#define SSH_FXP_REALPATH 16 +#define SSH_FXP_STAT 17 +#define SSH_FXP_RENAME 18 + +/* server to client */ +#define SSH_FXP_VERSION 2 +#define SSH_FXP_STATUS 101 +#define SSH_FXP_HANDLE 102 +#define SSH_FXP_DATA 103 +#define SSH_FXP_NAME 104 +#define SSH_FXP_ATTRS 105 + +/* portable open modes */ +#define SSH_FXF_READ 0x01 +#define SSH_FXF_WRITE 0x02 +#define SSH_FXF_APPEND 0x04 +#define SSH_FXF_CREAT 0x08 +#define SSH_FXF_TRUNC 0x10 +#define SSH_FXF_EXCL 0x20 + +/* attributes */ +#define SSH_FXA_HAVE_SIZE 0x01 +#define SSH_FXA_HAVE_UGID 0x02 +#define SSH_FXA_HAVE_PERM 0x04 +#define SSH_FXA_HAVE_TIME 0x08 + +/* status messages */ +#define SSH_FX_OK 0x00 +#define SSH_FX_EOF 0x01 +#define SSH_FX_NO_SUCH_FILE 0x02 +#define SSH_FX_PERMISSION_DENIED 0x03 +#define SSH_FX_FAILURE 0x04 +#define SSH_FX_BAD_MESSAGE 0x05 +#define SSH_FX_NO_CONNECTION 0x06 +#define SSH_FX_CONNECTION_LOST 0x07 + + +/* helper */ +#define get_int() buffer_get_int(&iqueue); +#define get_string(lenp) buffer_get_string(&iqueue, lenp); +#define TRACE log + +/* input and output queue */ +Buffer iqueue; +Buffer oqueue; + +/* portable attibutes, etc. */ + +typedef struct Attrib Attrib; +typedef struct Stat Stat; + +struct Attrib +{ + u_int32_t flags; + u_int32_t size_high; + u_int32_t size_low; + u_int64_t size; + u_int32_t uid; + u_int32_t gid; + u_int32_t perm; + u_int32_t atime; + u_int32_t mtime; +}; + +struct Stat +{ + char *name; + char *long_name; + Attrib attrib; +}; + +int +errno_to_portable(int unixerrno) +{ + int ret = 0; + switch (unixerrno) { + case 0: + ret = SSH_FX_OK; + break; + case ENOENT: + case ENOTDIR: + case EBADF: + case ELOOP: + ret = SSH_FX_NO_SUCH_FILE; + break; + case EPERM: + case EACCES: + case EFAULT: + ret = SSH_FX_PERMISSION_DENIED; + break; + case ENAMETOOLONG: + case EINVAL: + ret = SSH_FX_BAD_MESSAGE; + break; + default: + ret = SSH_FX_FAILURE; + break; + } + return ret; +} + +int +flags_from_portable(int pflags) +{ + int flags = 0; + if (pflags & SSH_FXF_READ && + pflags & SSH_FXF_WRITE) { + flags = O_RDWR; + } else if (pflags & SSH_FXF_READ) { + flags = O_RDONLY; + } else if (pflags & SSH_FXF_WRITE) { + flags = O_WRONLY; + } + if (pflags & SSH_FXF_CREAT) + flags |= O_CREAT; + if (pflags & SSH_FXF_TRUNC) + flags |= O_TRUNC; + if (pflags & SSH_FXF_EXCL) + flags |= O_EXCL; + return flags; +} + +void +attrib_clear(Attrib *a) +{ + a->flags = 0; + a->size_low = 0; + a->size_high = 0; + a->size = 0; + a->uid = 0; + a->gid = 0; + a->perm = 0; + a->atime = 0; + a->mtime = 0; +} + +Attrib * +decode_attrib(Buffer *b) +{ + static Attrib a; + attrib_clear(&a); + a.flags = get_int(); + if (a.flags & SSH_FXA_HAVE_SIZE) { + a.size_high = get_int(); + a.size_low = get_int(); + a.size = (((u_int64_t) a.size_high) << 32) + a.size_low; + } + if (a.flags & SSH_FXA_HAVE_UGID) { + a.uid = get_int(); + a.gid = get_int(); + } + if (a.flags & SSH_FXA_HAVE_PERM) { + a.perm = get_int(); + } + if (a.flags & SSH_FXA_HAVE_TIME) { + a.atime = get_int(); + a.mtime = get_int(); + } + return &a; +} + +void +encode_attrib(Buffer *b, Attrib *a) +{ + buffer_put_int(b, a->flags); + if (a->flags & SSH_FXA_HAVE_SIZE) { + buffer_put_int(b, a->size_high); + buffer_put_int(b, a->size_low); + } + if (a->flags & SSH_FXA_HAVE_UGID) { + buffer_put_int(b, a->uid); + buffer_put_int(b, a->gid); + } + if (a->flags & SSH_FXA_HAVE_PERM) { + buffer_put_int(b, a->perm); + } + if (a->flags & SSH_FXA_HAVE_TIME) { + buffer_put_int(b, a->atime); + buffer_put_int(b, a->mtime); + } +} + +Attrib * +stat_to_attrib(struct stat *st) +{ + static Attrib a; + attrib_clear(&a); + a.flags = 0; + a.flags |= SSH_FXA_HAVE_SIZE; + a.size = st->st_size; + a.size_low = a.size; + a.size_high = (u_int32_t) (a.size >> 32); + a.flags |= SSH_FXA_HAVE_UGID; + a.uid = st->st_uid; + a.gid = st->st_gid; + a.flags |= SSH_FXA_HAVE_PERM; + a.perm = st->st_mode; + a.flags |= SSH_FXA_HAVE_TIME; + a.atime = st->st_atime; + a.mtime = st->st_mtime; + return &a; +} + +Attrib * +get_attrib(void) +{ + return decode_attrib(&iqueue); +} + +/* handle handles */ + +typedef struct Handle Handle; +struct Handle { + int use; + DIR *dirp; + int fd; + char *name; +}; +enum { + HANDLE_UNUSED, + HANDLE_DIR, + HANDLE_FILE +}; +Handle handles[100]; + +void +handle_init(void) +{ + int i; + for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) + handles[i].use = HANDLE_UNUSED; +} + +int +handle_new(int use, char *name, int fd, DIR *dirp) +{ + int i; + for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) { + if (handles[i].use == HANDLE_UNUSED) { + handles[i].use = use; + handles[i].dirp = dirp; + handles[i].fd = fd; + handles[i].name = name; + return i; + } + } + return -1; +} + +int +handle_is_ok(int i, int type) +{ + return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type; +} + +int +handle_to_string(int handle, char **stringp, int *hlenp) +{ + char buf[1024]; + if (stringp == NULL || hlenp == NULL) + return -1; + snprintf(buf, sizeof buf, "%d", handle); + *stringp = xstrdup(buf); + *hlenp = strlen(*stringp); + return 0; +} + +int +handle_from_string(char *handle, int hlen) +{ +/* XXX OVERFLOW ? */ + char *ep; + long lval = strtol(handle, &ep, 10); + int val = lval; + if (*ep != '\0') + return -1; + if (handle_is_ok(val, HANDLE_FILE) || + handle_is_ok(val, HANDLE_DIR)) + return val; + return -1; +} + +char * +handle_to_name(int handle) +{ + if (handle_is_ok(handle, HANDLE_DIR)|| + handle_is_ok(handle, HANDLE_FILE)) + return handles[handle].name; + return NULL; +} + +DIR * +handle_to_dir(int handle) +{ + if (handle_is_ok(handle, HANDLE_DIR)) + return handles[handle].dirp; + return NULL; +} + +int +handle_to_fd(int handle) +{ + if (handle_is_ok(handle, HANDLE_FILE)) + return handles[handle].fd; + return -1; +} + +int +handle_close(int handle) +{ + int ret = -1; + if (handle_is_ok(handle, HANDLE_FILE)) { + ret = close(handles[handle].fd); + handles[handle].use = HANDLE_UNUSED; + } else if (handle_is_ok(handle, HANDLE_DIR)) { + ret = closedir(handles[handle].dirp); + handles[handle].use = HANDLE_UNUSED; + } else { + errno = ENOENT; + } + return ret; +} + +int +get_handle(void) +{ + char *handle; + int hlen, val; + handle = get_string(&hlen); + val = handle_from_string(handle, hlen); + xfree(handle); + return val; +} + +/* send replies */ + +void +send_msg(Buffer *m) +{ + int mlen = buffer_len(m); + buffer_put_int(&oqueue, mlen); + buffer_append(&oqueue, buffer_ptr(m), mlen); + buffer_consume(m, mlen); +} + +void +send_status(u_int32_t id, u_int32_t error) +{ + Buffer msg; + TRACE("sent status id %d error %d", id, error); + buffer_init(&msg); + buffer_put_char(&msg, SSH_FXP_STATUS); + buffer_put_int(&msg, id); + buffer_put_int(&msg, error); + send_msg(&msg); + buffer_free(&msg); +} +void +send_data_or_handle(char type, u_int32_t id, char *data, int dlen) +{ + Buffer msg; + buffer_init(&msg); + buffer_put_char(&msg, type); + buffer_put_int(&msg, id); + buffer_put_string(&msg, data, dlen); + send_msg(&msg); + buffer_free(&msg); +} + +void +send_data(u_int32_t id, char *data, int dlen) +{ + TRACE("sent data id %d len %d", id, dlen); + send_data_or_handle(SSH_FXP_DATA, id, data, dlen); +} + +void +send_handle(u_int32_t id, int handle) +{ + char *string; + int hlen; + handle_to_string(handle, &string, &hlen); + TRACE("sent handle id %d handle %d", id, handle); + send_data_or_handle(SSH_FXP_HANDLE, id, string, hlen); + xfree(string); +} + +void +send_names(u_int32_t id, int count, Stat *stats) +{ + Buffer msg; + int i; + buffer_init(&msg); + buffer_put_char(&msg, SSH_FXP_NAME); + buffer_put_int(&msg, id); + buffer_put_int(&msg, count); + TRACE("sent names id %d count %d", id, count); + for (i = 0; i < count; i++) { + buffer_put_cstring(&msg, stats[i].name); + buffer_put_cstring(&msg, stats[i].long_name); + encode_attrib(&msg, &stats[i].attrib); + } + send_msg(&msg); + buffer_free(&msg); +} + +void +send_attrib(u_int32_t id, Attrib *a) +{ + Buffer msg; + TRACE("sent attrib id %d have 0x%x", id, a->flags); + buffer_init(&msg); + buffer_put_char(&msg, SSH_FXP_ATTRS); + buffer_put_int(&msg, id); + encode_attrib(&msg, a); + send_msg(&msg); + buffer_free(&msg); +} + +/* parse incoming */ + +void +process_init(void) +{ + Buffer msg; + int version = buffer_get_int(&iqueue); + + TRACE("client version %d", version); + buffer_init(&msg); + buffer_put_char(&msg, SSH_FXP_VERSION); + buffer_put_int(&msg, SSH_FILEXFER_VERSION); + send_msg(&msg); + buffer_free(&msg); +} + +void +process_open(void) +{ + u_int32_t id, pflags; + Attrib *a; + char *name; + int handle, fd, flags, mode, status = SSH_FX_FAILURE; + + id = get_int(); + name = get_string(NULL); + pflags = get_int(); + a = get_attrib(); + flags = flags_from_portable(pflags); + mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm : 0666; + TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode); + fd = open(name, flags, mode); + if (fd < 0) { |