]> andersk Git - openssh.git/commitdiff
20000905
authordjm <djm>
Tue, 5 Sep 2000 02:34:53 +0000 (02:34 +0000)
committerdjm <djm>
Tue, 5 Sep 2000 02:34:53 +0000 (02:34 +0000)
 - (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

15 files changed:
ChangeLog
Makefile.in
README.openssh2
authfd.c
configure.in
scp.1
scp.c
session.c
sftp-server.8 [new file with mode: 0644]
sftp-server.c [new file with mode: 0644]
ssh-add.1
ssh-agent.c
ssh.1
sshd.8
sshd_config

index da17a9c12e16426f2a67f27a951205939153583e..9aa9423c84a7b711dac9aa49f7f83f3a340854d2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
 
index 4ceef7043fa5a6fdd636551e0813f78241553b99..7eb84ce63e0188b25a914e8ffd5481a5c757dbfb 100644 (file)
@@ -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
index 9c034aebd9a8f4e12bf2310d2f188e22e46f5330..01837bd122aece75f7fbd3a44554238cfee629a7 100644 (file)
@@ -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$
index d9427d3776acce1e1d36d8729124bf76c1ed0f43..6c40afc65e81a30ba06e2c5225f958cdf9dcfe25 100644 (file)
--- a/authfd.c
+++ b/authfd.c
@@ -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) {
index 33b82895b062dad6a2e6c10229b7a1b3781d34d6..b1dd1d0678ac8dc5d513bd609d58d184899ec66d 100644 (file)
@@ -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
diff --git a/scp.1 b/scp.1
index 54ca0f4bf375517a49c561e6a104bfbf51030c4f..9ae2ab64cbed5a4b0df3bf7189a8b13a71410d07 100644 (file)
--- a/scp.1
+++ b/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
diff --git a/scp.c b/scp.c
index 3b356a9c0a0da8ffbfccefd5da668300cd1c6cf3..33bd0a5ff7ad40cde3a7c7b57c9b39010f7ec773 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -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':
index 3678b8f090ac0a186a875a3c5ea11a91bfca0df9..d5faf4cf3d1de5750c3689454d98ac680e5d7c57 100644 (file)
--- a/session.c
+++ b/session.c
@@ -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 (file)
index 0000000..85720a0
--- /dev/null
@@ -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 (file)
index 0000000..39cecac
--- /dev/null
@@ -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) {
+               status = errno_to_portable(errno);
+       } else {
+               handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);
+               if (handle < 0) {
+                       close(fd);
+               } else {
+                       send_handle(id, handle);
+                       status = SSH_FX_OK;
+               }
+       }
+       if (status != SSH_FX_OK)
+               send_status(id, status);
+       xfree(name);
+}
+
+void
+process_close(void)
+{
+       u_int32_t id;
+       int handle, ret, status = SSH_FX_FAILURE;
+
+       id = get_int();
+       handle = get_handle();
+       TRACE("close id %d handle %d", id, handle);
+       ret = handle_close(handle);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
+       send_status(id, status);
+}
+
+void
+process_read(void)
+{
+       char buf[64*1024];
+       u_int32_t id, off_high, off_low, len;
+       int handle, fd, ret, status = SSH_FX_FAILURE;
+       u_int64_t off;
+
+       id = get_int();
+       handle = get_handle();
+       off_high = get_int();
+       off_low = get_int();
+       len = get_int();
+
+       off = (((u_int64_t) off_high) << 32) + off_low;
+       TRACE("read id %d handle %d off %qd len %d", id, handle, off, len);
+       if (len > sizeof buf) {
+               len = sizeof buf;
+               log("read change len %d", len);
+       }
+       fd = handle_to_fd(handle);
+       if (fd >= 0) {
+               if (lseek(fd, off, SEEK_SET) < 0) {
+                       error("process_read: seek failed");
+                       status = errno_to_portable(errno);
+               } else {
+                       ret = read(fd, buf, len);
+                       if (ret < 0) {
+                               status = errno_to_portable(errno);
+                       } else if (ret == 0) {
+                               status = SSH_FX_EOF;
+                       } else {
+                               send_data(id, buf, ret);
+                               status = SSH_FX_OK;
+                       }
+               }
+       }
+       if (status != SSH_FX_OK)
+               send_status(id, status);
+}
+
+void
+process_write(void)
+{
+       u_int32_t id, off_high, off_low;
+       u_int64_t off;
+       int len;
+       int handle, fd, ret, status = SSH_FX_FAILURE;
+       char *data;
+
+       id = get_int();
+       handle = get_handle();
+       off_high = get_int();
+       off_low = get_int();
+       data = get_string(&len);
+
+       off = (((u_int64_t) off_high) << 32) + off_low;
+       TRACE("write id %d handle %d off %qd len %d", id, handle, off, len);
+       fd = handle_to_fd(handle);
+       if (fd >= 0) {
+               if (lseek(fd, off, SEEK_SET) < 0) {
+                       status = errno_to_portable(errno);
+                       error("process_write: seek failed");
+               } else {
+/* XXX ATOMICIO ? */
+                       ret = write(fd, data, len);
+                       if (ret == -1) {
+                               error("process_write: write failed");
+                               status = errno_to_portable(errno);
+                       } else if (ret == len) {
+                               status = SSH_FX_OK;
+                       } else {
+                               log("nothing at all written");
+                       }
+               }
+       }
+       send_status(id, status);
+       xfree(data);
+}
+
+void
+process_do_stat(int do_lstat)
+{
+       Attrib *a;
+       struct stat st;
+       u_int32_t id;
+       char *name;
+       int ret, status = SSH_FX_FAILURE;
+
+       id = get_int();
+       name = get_string(NULL);
+       TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
+       ret = do_lstat ? lstat(name, &st) : stat(name, &st);
+       if (ret < 0) {
+               status = errno_to_portable(errno);
+       } else {
+               a = stat_to_attrib(&st);
+               send_attrib(id, a);
+               status = SSH_FX_OK;
+       }
+       if (status != SSH_FX_OK)
+               send_status(id, status);
+       xfree(name);
+}
+
+void
+process_stat(void)
+{
+       process_do_stat(0);
+}
+
+void
+process_lstat(void)
+{
+       process_do_stat(1);
+}
+
+void
+process_fstat(void)
+{
+       Attrib *a;
+       struct stat st;
+       u_int32_t id;
+       int fd, ret, handle, status = SSH_FX_FAILURE;
+
+       id = get_int();
+       handle = get_handle();
+       TRACE("fstat id %d handle %d", id, handle);
+       fd = handle_to_fd(handle);
+       if (fd  >= 0) {
+               ret = fstat(fd, &st);
+               if (ret < 0) {
+                       status = errno_to_portable(errno);
+               } else {
+                       a = stat_to_attrib(&st);
+                       send_attrib(id, a);
+                       status = SSH_FX_OK;
+               }
+       }
+       if (status != SSH_FX_OK)
+               send_status(id, status);
+}
+
+struct timeval *
+attrib_to_tv(Attrib *a)
+{
+       static struct timeval tv[2];
+       tv[0].tv_sec = a->atime;
+       tv[0].tv_usec = 0;
+       tv[1].tv_sec = a->mtime;
+       tv[1].tv_usec = 0;
+       return tv;
+}
+
+void
+process_setstat(void)
+{
+       Attrib *a;
+       u_int32_t id;
+       char *name;
+       int ret;
+       int status = SSH_FX_OK;
+
+       id = get_int();
+       name = get_string(NULL);
+       a = get_attrib();
+       TRACE("setstat id %d name %s", id, name);
+       if (a->flags & SSH_FXA_HAVE_PERM) {
+               ret = chmod(name, a->perm & 0777);
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       if (a->flags & SSH_FXA_HAVE_TIME) {
+               ret = utimes(name, attrib_to_tv(a));
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       send_status(id, status);
+       xfree(name);
+}
+
+void
+process_fsetstat(void)
+{
+       Attrib *a;
+       u_int32_t id;
+       int handle, fd, ret;
+       int status = SSH_FX_OK;
+       char *name = NULL;
+
+       id = get_int();
+       handle = get_handle();
+       a = get_attrib();
+       TRACE("fsetstat id %d handle %d", id, handle);
+       fd = handle_to_fd(handle);
+       name = handle_to_name(handle);
+       if ((fd < 0) || (name == NULL)) {
+               status = SSH_FX_FAILURE;
+       } else {
+               if (a->flags & SSH_FXA_HAVE_PERM) {
+                       ret = fchmod(fd, a->perm & 0777);
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+               if (a->flags & SSH_FXA_HAVE_TIME) {
+#ifdef HAVE_FUTIMES
+                       ret = futimes(fd, attrib_to_tv(a));
+#else
+                       ret = utimes(name, attrib_to_tv(a));
+#endif
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+       }
+       send_status(id, status);
+}
+
+void
+process_opendir(void)
+{
+       DIR *dirp = NULL;
+       char *path;
+       int handle, status = SSH_FX_FAILURE;
+       u_int32_t id;
+
+       id = get_int();
+       path = get_string(NULL);
+       TRACE("opendir id %d path %s", id, path);
+       dirp = opendir(path); 
+       if (dirp == NULL) {
+               status = errno_to_portable(errno);
+       } else {
+               handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp);
+               if (handle < 0) {
+                       closedir(dirp);
+               } else {
+                       send_handle(id, handle);
+                       status = SSH_FX_OK;
+               }
+               
+       }
+       if (status != SSH_FX_OK)
+               send_status(id, status);
+       xfree(path);
+}
+
+char *
+ls_file(char *name, struct stat *st)
+{
+       char buf[1024];
+       snprintf(buf, sizeof buf, "0%o %d %d %qd %d %s",
+           st->st_mode, st->st_uid, st->st_gid, (long long)st->st_size,(int) st->st_mtime,
+           name);
+       return xstrdup(buf);
+}
+
+void
+process_readdir(void)
+{
+       DIR *dirp;
+       struct dirent *dp;
+       char *path;
+       int handle;
+       u_int32_t id;
+
+       id = get_int();
+       handle = get_handle();
+       TRACE("readdir id %d handle %d", id, handle);
+       dirp = handle_to_dir(handle);
+       path = handle_to_name(handle);
+       if (dirp == NULL || path == NULL) {
+               send_status(id, SSH_FX_FAILURE);
+       } else {
+               Attrib *a;
+               struct stat st;
+               char pathname[1024];
+               Stat *stats;
+               int nstats = 10, count = 0, i;
+               stats = xmalloc(nstats * sizeof(Stat));
+               while ((dp = readdir(dirp)) != NULL) {
+                       if (count >= nstats) {
+                               nstats *= 2;
+                               stats = xrealloc(stats, nstats * sizeof(Stat));
+                       }
+/* XXX OVERFLOW ? */
+                       snprintf(pathname, sizeof pathname,
+                           "%s/%s", path, dp->d_name);
+                       if (lstat(pathname, &st) < 0)
+                               continue;
+                       a = stat_to_attrib(&st);
+                       stats[count].attrib = *a;
+                       stats[count].name = xstrdup(dp->d_name);
+                       stats[count].long_name = ls_file(dp->d_name, &st);
+                       count++;
+                       /* send up to 100 entries in one message */
+                       if (count == 100)
+                               break;
+               }
+               send_names(id, count, stats);
+               for(i = 0; i < count; i++) {
+                       xfree(stats[i].name);
+                       xfree(stats[i].long_name);
+               }
+               xfree(stats);
+       }
+}
+
+void
+process_remove(void)
+{
+       char *name;
+       u_int32_t id;
+       int status = SSH_FX_FAILURE;
+       int ret;
+
+       id = get_int();
+       name = get_string(NULL);
+       TRACE("remove id %d name %s", id, name);
+       ret = remove(name);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
+       send_status(id, status);
+       xfree(name);
+}
+
+void
+process_mkdir(void)
+{
+       Attrib *a;
+       u_int32_t id;
+       char *name;
+       int ret, mode, status = SSH_FX_FAILURE;
+
+       id = get_int();
+       name = get_string(NULL);
+       a = get_attrib();
+       mode = (a->flags & SSH_FXA_HAVE_PERM) ? a->perm & 0777 : 0777;
+       TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
+       ret = mkdir(name, mode);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
+       send_status(id, status);
+       xfree(name);
+}
+
+void
+process_rmdir(void)
+{
+       u_int32_t id;
+       char *name;
+       int ret, status;
+
+       id = get_int();
+       name = get_string(NULL);
+       TRACE("rmdir id %d name %s", id, name);
+       ret = rmdir(name);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
+       send_status(id, status);
+       xfree(name);
+}
+
+void
+process_realpath(void)
+{
+       char resolvedname[MAXPATHLEN];
+       u_int32_t id;
+       char *path;
+
+       id = get_int();
+       path = get_string(NULL);
+       TRACE("realpath id %d path %s", id, path);
+       if (realpath(path, resolvedname) == NULL) {
+               send_status(id, errno_to_portable(errno));
+       } else {
+               Stat s;
+               attrib_clear(&s.attrib);
+               s.name = s.long_name = resolvedname;
+               send_names(id, 1, &s);
+       }
+       xfree(path);
+}
+
+void
+process_rename(void)
+{
+       u_int32_t id;
+       char *oldpath, *newpath;
+       int ret, status;
+
+       id = get_int();
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       TRACE("rename id %d old %s new %s", id, oldpath, newpath);
+       ret = rename(oldpath, newpath);
+       status = (ret == -1) ? errno_to_portable(errno) : SSH_FX_OK;
+       send_status(id, status);
+       xfree(oldpath);
+       xfree(newpath);
+}
+
+
+/* stolen from ssh-agent */
+
+void
+process(void)
+{
+       unsigned int msg_len;
+       unsigned int type;
+       unsigned char *cp;
+
+       if (buffer_len(&iqueue) < 5)
+               return;         /* Incomplete message. */
+       cp = (unsigned char *) buffer_ptr(&iqueue);
+       msg_len = GET_32BIT(cp);
+       if (msg_len > 256 * 1024) {
+               error("bad message ");
+               exit(11);
+       }
+       if (buffer_len(&iqueue) < msg_len + 4)
+               return;
+       buffer_consume(&iqueue, 4);
+       type = buffer_get_char(&iqueue);
+       switch (type) {
+       case SSH_FXP_INIT:
+               process_init();
+               break;
+       case SSH_FXP_OPEN:
+               process_open();
+               break;
+       case SSH_FXP_CLOSE:
+               process_close();
+               break;
+       case SSH_FXP_READ:
+               process_read();
+               break;
+       case SSH_FXP_WRITE:
+               process_write();
+               break;
+       case SSH_FXP_LSTAT:
+               process_lstat();
+               break;
+       case SSH_FXP_FSTAT:
+               process_fstat();
+               break;
+       case SSH_FXP_SETSTAT:
+               process_setstat();
+               break;
+       case SSH_FXP_FSETSTAT:
+               process_fsetstat();
+               break;
+       case SSH_FXP_OPENDIR:
+               process_opendir();
+               break;
+       case SSH_FXP_READDIR:
+               process_readdir();
+               break;
+       case SSH_FXP_REMOVE:
+               process_remove();
+               break;
+       case SSH_FXP_MKDIR:
+               process_mkdir();
+               break;
+       case SSH_FXP_RMDIR:
+               process_rmdir();
+               break;
+       case SSH_FXP_REALPATH:
+               process_realpath();
+               break;
+       case SSH_FXP_STAT:
+               process_stat();
+               break;
+       case SSH_FXP_RENAME:
+               process_rename();
+               break;
+       default:
+               error("Unknown message %d", type);
+               break;
+       }
+}
+
+int
+main(int ac, char **av)
+{
+       fd_set rset, wset;
+       int in, out, max;
+       size_t len, olen;
+
+       handle_init();
+
+       in = dup(STDIN_FILENO);
+       out = dup(STDOUT_FILENO);
+
+       max = 0;
+       if (in > max)
+               max = in;
+       if (out > max)
+               max = out;
+
+       buffer_init(&iqueue);
+       buffer_init(&oqueue);
+
+       for (;;) {
+               FD_ZERO(&rset);
+               FD_ZERO(&wset);
+
+               FD_SET(in, &rset);
+               olen = buffer_len(&oqueue);
+               if (olen > 0)
+                       FD_SET(out, &wset);
+
+               if (select(max+1, &rset, &wset, NULL, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       exit(2);
+               }
+
+               /* copy stdin to iqueue */
+               if (FD_ISSET(in, &rset)) {
+                       char buf[4*4096];
+                       len = read(in, buf, sizeof buf);
+                       if (len == 0) {
+                               debug("read eof");
+                               exit(0);
+                       } else if (len < 0) {
+                               error("read error");
+                               exit(1);
+                       } else {
+                               buffer_append(&iqueue, buf, len);
+                       }
+               }
+               /* send oqueue to stdout */
+               if (FD_ISSET(out, &wset)) {
+                       len = write(out, buffer_ptr(&oqueue), olen);
+                       if (len < 0) {
+                               error("write error");
+                               exit(1);
+                       } else {
+                               buffer_consume(&oqueue, len);
+                       }
+               }
+               /* process requests from client */
+               process();
+       }
+}
index b5dae10de62671a5494f3658c908aee91ec38ee2..f0c31a272e2138157cb776584f6a0be449d5bd2f 100644 (file)
--- a/ssh-add.1
+++ b/ssh-add.1
@@ -65,7 +65,7 @@ This is the default file added by
 when no other files have been specified.
 .It Pa $HOME/.ssh/id_dsa
 Contains the DSA authentication identity of the user.
-.Pp
+.El
 .Sh ENVIRONMENT
 .Bl -tag -width Ds
 .It Ev "DISPLAY" and "SSH_ASKPASS"
@@ -91,6 +91,7 @@ or related script.
 may be necessary to redirect the input from
 .Pa /dev/null
 to make this work.)
+.El
 .Sh AUTHOR
 Tatu Ylonen <ylo@cs.hut.fi>
 .Pp
index 56b81a78db8e22b37915299890a8336b372d2d8d..0bc4722b2a4d15cbdc7167a384e5e1660cd00f43 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $   */
+/*     $OpenBSD: ssh-agent.c,v 1.34 2000/08/31 22:09:34 markus Exp $   */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh-agent.c,v 1.33 2000/08/19 21:34:43 markus Exp $");
+RCSID("$OpenBSD: ssh-agent.c,v 1.34 2000/08/31 22:09:34 markus Exp $");
 
 #include "ssh.h"
 #include "rsa.h"
@@ -219,6 +219,7 @@ process_sign_request2(SocketEntry *e)
        
        blob = buffer_get_string(&e->input, &blen);
        data = buffer_get_string(&e->input, &dlen);
+       buffer_get_int(&e->input);                      /* flags, unused */
 
        key = dsa_key_from_blob(blob, blen);
        if (key != NULL) {
diff --git a/ssh.1 b/ssh.1
index 58bbb7016db4d3ca566bdd428a18606157217e3b..7c04c0e9814c9e747b102202f428d0b9ebbe94c4 100644 (file)
--- a/ssh.1
+++ b/ssh.1
@@ -946,6 +946,7 @@ Specifies the location of the
 program.
 The default is
 .Pa /usr/X11R6/bin/xauth .
+.El
 .Sh ENVIRONMENT
 .Nm
 will normally set the following environment variables:
@@ -1189,6 +1190,7 @@ above.
 .It Pa libcrypto.so.X.1
 A version of this library which includes support for the RSA algorithm
 is required for proper operation.
+.El
 .Sh AUTHOR
 OpenSSH
 is a derivative of the original (free) ssh 1.2.12 release by Tatu Ylonen,
diff --git a/sshd.8 b/sshd.8
index b5c2aeff13638c12aeb1fdda81dd30b53ad5d01f..aedaa03125e4558239ff525487a33946c7cce5b2 100644 (file)
--- a/sshd.8
+++ b/sshd.8
@@ -589,6 +589,11 @@ The default is
 .It Cm Subsystem
 Configures an external subsystem (e.g. file transfer daemon).
 Arguments should be a subsystem name and a command to execute upon subsystem request. 
+The command
+.Xr sftp-server 8
+implements the
+.Dq sftp
+file transfer subsystem.
 By default no subsystems are defined.
 Note that this option applies to protocol version 2 only.
 .It Cm SyslogFacility
@@ -1031,6 +1036,7 @@ Niels Provos, Theo de Raadt, and Dug Song.
 The support for SSH protocol 2 was written by Markus Friedl.
 .Sh SEE ALSO
 .Xr scp 1 ,
+.Xr sftp-server 8 ,
 .Xr ssh 1 ,
 .Xr ssh-add 1 ,
 .Xr ssh-agent 1 ,
index b89b19fc8e6fdff6f3edf2897ffb3c7670c41acb..43d2e8ea6b49f9b8f2a0305079f9abf45b1d0cd3 100644 (file)
@@ -50,5 +50,6 @@ PermitEmptyPasswords no
 CheckMail no
 #UseLogin no
 
-#Subsystem     sftp    /usr/local/sbin/sftpd
+# Uncomment if you want to enable sftp
+#Subsystem     sftp    /usr/libexec/sftp-server
 #MaxStartups 10:30:60
This page took 1.150201 seconds and 5 git commands to generate.