403Webshell
Server IP : 81.2.241.106  /  Your IP : 216.73.216.165
Web Server : Apache/2.4.67 (Debian)
System : Linux tranq-f.bakta.org 5.10.0-45-amd64 #1 SMP Debian 5.10.259-1 (2026-07-02) x86_64
User : lisky ( 1002)
PHP Version : 7.4.33
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /usr/src/openssh-chroot/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /usr/src/openssh-chroot/sftp-server.diff
--- sftp-server.c	2008-02-25 13:54:58.933872430 +0100
+++ openssh-4.7p1/sftp-server.c	2007-05-20 07:09:05.000000000 +0200
@@ -1,3 +1,4 @@
+/* $OpenBSD: sftp-server.c,v 1.73 2007/05/17 07:55:29 djm Exp $ */
 /*
  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
  *
@@ -13,31 +14,48 @@
  * 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"
-RCSID("$OpenBSD: sftp-server.c,v 1.45 2004/02/19 21:15:04 markus Exp $");
 
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
 #include "buffer.h"
-#include "bufaux.h"
-#include "getput.h"
 #include "log.h"
-#include "xmalloc.h"
+#include "misc.h"
+#include "uidswap.h"
 
 #include "sftp.h"
 #include "sftp-common.h"
 
-#define CHROOT
-
 /* helper */
 #define get_int64()			buffer_get_int64(&iqueue);
 #define get_int()			buffer_get_int(&iqueue);
 #define get_string(lenp)		buffer_get_string(&iqueue, lenp);
-#define TRACE				debug
 
-#ifdef HAVE___PROGNAME
-extern char *__progname;
-#else
-char *__progname;
-#endif
+/* Our verbosity */
+LogLevel log_level = SYSLOG_LEVEL_ERROR;
+
+/* Our client */
+struct passwd *pw = NULL;
+char *client_addr = NULL;
 
 /* input and output queue */
 Buffer iqueue;
@@ -109,6 +127,33 @@
 	return flags;
 }
 
+static const char *
+string_from_portable(int pflags)
+{
+	static char ret[128];
+
+	*ret = '\0';
+
+#define PAPPEND(str)	{				\
+		if (*ret != '\0')			\
+			strlcat(ret, ",", sizeof(ret));	\
+		strlcat(ret, str, sizeof(ret));		\
+	}
+
+	if (pflags & SSH2_FXF_READ)
+		PAPPEND("READ")
+	if (pflags & SSH2_FXF_WRITE)
+		PAPPEND("WRITE")
+	if (pflags & SSH2_FXF_CREAT)
+		PAPPEND("CREATE")
+	if (pflags & SSH2_FXF_TRUNC)
+		PAPPEND("TRUNCATE")
+	if (pflags & SSH2_FXF_EXCL)
+		PAPPEND("EXCL")
+
+	return ret;
+}
+
 static Attrib *
 get_attrib(void)
 {
@@ -123,6 +168,7 @@
 	DIR *dirp;
 	int fd;
 	char *name;
+	u_int64_t bytes_read, bytes_write;
 };
 
 enum {
@@ -136,7 +182,7 @@
 static void
 handle_init(void)
 {
-	int i;
+	u_int i;
 
 	for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
 		handles[i].use = HANDLE_UNUSED;
@@ -145,7 +191,7 @@
 static int
 handle_new(int use, const char *name, int fd, DIR *dirp)
 {
-	int i;
+	u_int i;
 
 	for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
 		if (handles[i].use == HANDLE_UNUSED) {
@@ -153,6 +199,7 @@
 			handles[i].dirp = dirp;
 			handles[i].fd = fd;
 			handles[i].name = xstrdup(name);
+			handles[i].bytes_read = handles[i].bytes_write = 0;
 			return i;
 		}
 	}
@@ -162,7 +209,7 @@
 static int
 handle_is_ok(int i, int type)
 {
-	return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
+	return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
 	    handles[i].use == type;
 }
 
@@ -172,7 +219,7 @@
 	if (stringp == NULL || hlenp == NULL)
 		return -1;
 	*stringp = xmalloc(sizeof(int32_t));
-	PUT_32BIT(*stringp, handle);
+	put_u32(*stringp, handle);
 	*hlenp = sizeof(int32_t);
 	return 0;
 }
@@ -184,7 +231,7 @@
 
 	if (hlen != sizeof(int32_t))
 		return -1;
-	val = GET_32BIT(handle);
+	val = get_u32(handle);
 	if (handle_is_ok(val, HANDLE_FILE) ||
 	    handle_is_ok(val, HANDLE_DIR))
 		return val;
@@ -216,6 +263,36 @@
 	return -1;
 }
 
+static void
+handle_update_read(int handle, ssize_t bytes)
+{
+	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
+		handles[handle].bytes_read += bytes;
+}
+
+static void
+handle_update_write(int handle, ssize_t bytes)
+{
+	if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
+		handles[handle].bytes_write += bytes;
+}
+
+static u_int64_t
+handle_bytes_read(int handle)
+{
+	if (handle_is_ok(handle, HANDLE_FILE))
+		return (handles[handle].bytes_read);
+	return 0;
+}
+
+static u_int64_t
+handle_bytes_write(int handle)
+{
+	if (handle_is_ok(handle, HANDLE_FILE))
+		return (handles[handle].bytes_write);
+	return 0;
+}
+
 static int
 handle_close(int handle)
 {
@@ -235,6 +312,32 @@
 	return ret;
 }
 
+static void
+handle_log_close(int handle, char *emsg)
+{
+	if (handle_is_ok(handle, HANDLE_FILE)) {
+		logit("%s%sclose \"%s\" bytes read %llu written %llu",
+		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
+		    handle_to_name(handle),
+		    (unsigned long long)handle_bytes_read(handle),
+		    (unsigned long long)handle_bytes_write(handle));
+	} else {
+		logit("%s%sclosedir \"%s\"",
+		    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
+		    handle_to_name(handle));
+	}
+}
+
+static void
+handle_log_exit(void)
+{
+	u_int i;
+
+	for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
+		if (handles[i].use != HANDLE_UNUSED)
+			handle_log_close(i, "forced");
+}
+
 static int
 get_handle(void)
 {
@@ -261,10 +364,9 @@
 	buffer_consume(m, mlen);
 }
 
-static void
-send_status(u_int32_t id, u_int32_t error)
+static const char *
+status_to_message(u_int32_t status)
 {
-	Buffer msg;
 	const char *status_messages[] = {
 		"Success",			/* SSH_FX_OK */
 		"End of file",			/* SSH_FX_EOF */
@@ -277,15 +379,24 @@
 		"Operation unsupported",	/* SSH_FX_OP_UNSUPPORTED */
 		"Unknown error"			/* Others */
 	};
+	return (status_messages[MIN(status,SSH2_FX_MAX)]);
+}
+
+static void
+send_status(u_int32_t id, u_int32_t status)
+{
+	Buffer msg;
 
-	TRACE("sent status id %u error %u", id, error);
+	debug3("request %u: sent status %u", id, status);
+	if (log_level > SYSLOG_LEVEL_VERBOSE ||
+	    (status != SSH2_FX_OK && status != SSH2_FX_EOF))
+		logit("sent status %s", status_to_message(status));
 	buffer_init(&msg);
 	buffer_put_char(&msg, SSH2_FXP_STATUS);
 	buffer_put_int(&msg, id);
-	buffer_put_int(&msg, error);
+	buffer_put_int(&msg, status);
 	if (version >= 3) {
-		buffer_put_cstring(&msg,
-		    status_messages[MIN(error,SSH2_FX_MAX)]);
+		buffer_put_cstring(&msg, status_to_message(status));
 		buffer_put_cstring(&msg, "");
 	}
 	send_msg(&msg);
@@ -307,7 +418,7 @@
 static void
 send_data(u_int32_t id, const char *data, int dlen)
 {
-	TRACE("sent data id %u len %d", id, dlen);
+	debug("request %u: sent data len %d", id, dlen);
 	send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
 }
 
@@ -318,7 +429,7 @@
 	int hlen;
 
 	handle_to_string(handle, &string, &hlen);
-	TRACE("sent handle id %u handle %d", id, handle);
+	debug("request %u: sent handle handle %d", id, handle);
 	send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
 	xfree(string);
 }
@@ -333,7 +444,7 @@
 	buffer_put_char(&msg, SSH2_FXP_NAME);
 	buffer_put_int(&msg, id);
 	buffer_put_int(&msg, count);
-	TRACE("sent names id %u count %d", id, count);
+	debug("request %u: sent names 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);
@@ -348,7 +459,7 @@
 {
 	Buffer msg;
 
-	TRACE("sent attrib id %u have 0x%x", id, a->flags);
+	debug("request %u: sent attrib have 0x%x", id, a->flags);
 	buffer_init(&msg);
 	buffer_put_char(&msg, SSH2_FXP_ATTRS);
 	buffer_put_int(&msg, id);
@@ -365,7 +476,7 @@
 	Buffer msg;
 
 	version = get_int();
-	TRACE("client version %d", version);
+	verbose("received client version %d", version);
 	buffer_init(&msg);
 	buffer_put_char(&msg, SSH2_FXP_VERSION);
 	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
@@ -384,10 +495,12 @@
 	id = get_int();
 	name = get_string(NULL);
 	pflags = get_int();		/* portable flags */
+	debug3("request %u: open flags %d", id, pflags);
 	a = get_attrib();
 	flags = flags_from_portable(pflags);
 	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
-	TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode);
+	logit("open \"%s\" flags %s mode 0%o",
+	    name, string_from_portable(pflags), mode);
 	fd = open(name, flags, mode);
 	if (fd < 0) {
 		status = errno_to_portable(errno);
@@ -413,7 +526,8 @@
 
 	id = get_int();
 	handle = get_handle();
-	TRACE("close id %u handle %d", id, handle);
+	debug3("request %u: close handle %u", id, handle);
+	handle_log_close(handle, NULL);
 	ret = handle_close(handle);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
@@ -432,11 +546,11 @@
 	off = get_int64();
 	len = get_int();
 
-	TRACE("read id %u handle %d off %llu len %d", id, handle,
-	    (u_int64_t)off, len);
+	debug("request %u: read \"%s\" (handle %d) off %llu len %d",
+	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
 	if (len > sizeof buf) {
 		len = sizeof buf;
-		logit("read change len %d", len);
+		debug2("read change len %d", len);
 	}
 	fd = handle_to_fd(handle);
 	if (fd >= 0) {
@@ -452,6 +566,7 @@
 			} else {
 				send_data(id, buf, ret);
 				status = SSH2_FX_OK;
+				handle_update_read(handle, ret);
 			}
 		}
 	}
@@ -473,8 +588,8 @@
 	off = get_int64();
 	data = get_string(&len);
 
-	TRACE("write id %u handle %d off %llu len %d", id, handle,
-	    (u_int64_t)off, len);
+	debug("request %u: write \"%s\" (handle %d) off %llu len %d",
+	    id, handle_to_name(handle), handle, (unsigned long long)off, len);
 	fd = handle_to_fd(handle);
 	if (fd >= 0) {
 		if (lseek(fd, off, SEEK_SET) < 0) {
@@ -483,13 +598,14 @@
 		} else {
 /* XXX ATOMICIO ? */
 			ret = write(fd, data, len);
-			if (ret == -1) {
+			if (ret < 0) {
 				error("process_write: write failed");
 				status = errno_to_portable(errno);
-			} else if (ret == len) {
+			} else if ((size_t)ret == len) {
 				status = SSH2_FX_OK;
+				handle_update_write(handle, ret);
 			} else {
-				logit("nothing at all written");
+				debug2("nothing at all written");
 			}
 		}
 	}
@@ -508,7 +624,8 @@
 
 	id = get_int();
 	name = get_string(NULL);
-	TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name);
+	debug3("request %u: %sstat", id, do_lstat ? "l" : "");
+	verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
 	ret = do_lstat ? lstat(name, &st) : stat(name, &st);
 	if (ret < 0) {
 		status = errno_to_portable(errno);
@@ -544,9 +661,10 @@
 
 	id = get_int();
 	handle = get_handle();
-	TRACE("fstat id %u handle %d", id, handle);
+	debug("request %u: fstat \"%s\" (handle %u)",
+	    id, handle_to_name(handle), handle);
 	fd = handle_to_fd(handle);
-	if (fd  >= 0) {
+	if (fd >= 0) {
 		ret = fstat(fd, &st);
 		if (ret < 0) {
 			status = errno_to_portable(errno);
@@ -583,23 +701,34 @@
 	id = get_int();
 	name = get_string(NULL);
 	a = get_attrib();
-	TRACE("setstat id %u name %s", id, name);
+	debug("request %u: setstat name \"%s\"", id, name);
 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
+		logit("set \"%s\" size %llu",
+		    name, (unsigned long long)a->size);
 		ret = truncate(name, a->size);
 		if (ret == -1)
 			status = errno_to_portable(errno);
 	}
 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
+		logit("set \"%s\" mode %04o", name, a->perm);
 		ret = chmod(name, a->perm & 0777);
 		if (ret == -1)
 			status = errno_to_portable(errno);
 	}
 	if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+		char buf[64];
+		time_t t = a->mtime;
+
+		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
+		    localtime(&t));
+		logit("set \"%s\" modtime %s", name, buf);
 		ret = utimes(name, attrib_to_tv(a));
 		if (ret == -1)
 			status = errno_to_portable(errno);
 	}
 	if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+		logit("set \"%s\" owner %lu group %lu", name,
+		    (u_long)a->uid, (u_long)a->gid);
 		ret = chown(name, a->uid, a->gid);
 		if (ret == -1)
 			status = errno_to_portable(errno);
@@ -615,23 +744,26 @@
 	u_int32_t id;
 	int handle, fd, ret;
 	int status = SSH2_FX_OK;
-	char *name;
 
 	id = get_int();
 	handle = get_handle();
 	a = get_attrib();
-	TRACE("fsetstat id %u handle %d", id, handle);
+	debug("request %u: fsetstat handle %d", id, handle);
 	fd = handle_to_fd(handle);
-	name = handle_to_name(handle);
-	if (fd < 0 || name == NULL) {
+	if (fd < 0) {
 		status = SSH2_FX_FAILURE;
 	} else {
+		char *name = handle_to_name(handle);
+
 		if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
+			logit("set \"%s\" size %llu",
+			    name, (unsigned long long)a->size);
 			ret = ftruncate(fd, a->size);
 			if (ret == -1)
 				status = errno_to_portable(errno);
 		}
 		if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
+			logit("set \"%s\" mode %04o", name, a->perm);
 #ifdef HAVE_FCHMOD
 			ret = fchmod(fd, a->perm & 0777);
 #else
@@ -641,6 +773,12 @@
 				status = errno_to_portable(errno);
 		}
 		if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+			char buf[64];
+			time_t t = a->mtime;
+
+			strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
+			    localtime(&t));
+			logit("set \"%s\" modtime %s", name, buf);
 #ifdef HAVE_FUTIMES
 			ret = futimes(fd, attrib_to_tv(a));
 #else
@@ -650,6 +788,8 @@
 				status = errno_to_portable(errno);
 		}
 		if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+			logit("set \"%s\" owner %lu group %lu", name,
+			    (u_long)a->uid, (u_long)a->gid);
 #ifdef HAVE_FCHOWN
 			ret = fchown(fd, a->uid, a->gid);
 #else
@@ -672,7 +812,8 @@
 
 	id = get_int();
 	path = get_string(NULL);
-	TRACE("opendir id %u path %s", id, path);
+	debug3("request %u: opendir", id);
+	logit("opendir \"%s\"", path);
 	dirp = opendir(path);
 	if (dirp == NULL) {
 		status = errno_to_portable(errno);
@@ -702,22 +843,23 @@
 
 	id = get_int();
 	handle = get_handle();
-	TRACE("readdir id %u handle %d", id, handle);
+	debug("request %u: readdir \"%s\" (handle %d)", id,
+	    handle_to_name(handle), handle);
 	dirp = handle_to_dir(handle);
 	path = handle_to_name(handle);
 	if (dirp == NULL || path == NULL) {
 		send_status(id, SSH2_FX_FAILURE);
 	} else {
 		struct stat st;
-		char pathname[1024];
+		char pathname[MAXPATHLEN];
 		Stat *stats;
 		int nstats = 10, count = 0, i;
 
-		stats = xmalloc(nstats * sizeof(Stat));
+		stats = xcalloc(nstats, sizeof(Stat));
 		while ((dp = readdir(dirp)) != NULL) {
 			if (count >= nstats) {
 				nstats *= 2;
-				stats = xrealloc(stats, nstats * sizeof(Stat));
+				stats = xrealloc(stats, nstats, sizeof(Stat));
 			}
 /* XXX OVERFLOW ? */
 			snprintf(pathname, sizeof pathname, "%s%s%s", path,
@@ -756,7 +898,8 @@
 
 	id = get_int();
 	name = get_string(NULL);
-	TRACE("remove id %u name %s", id, name);
+	debug3("request %u: remove", id);
+	logit("remove name \"%s\"", name);
 	ret = unlink(name);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
@@ -776,7 +919,8 @@
 	a = get_attrib();
 	mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
 	    a->perm & 0777 : 0777;
-	TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
+	debug3("request %u: mkdir", id);
+	logit("mkdir name \"%s\" mode 0%o", name, mode);
 	ret = mkdir(name, mode);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
@@ -792,7 +936,8 @@
 
 	id = get_int();
 	name = get_string(NULL);
-	TRACE("rmdir id %u name %s", id, name);
+	debug3("request %u: rmdir", id);
+	logit("rmdir name \"%s\"", name);
 	ret = rmdir(name);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
 	send_status(id, status);
@@ -812,7 +957,8 @@
 		xfree(path);
 		path = xstrdup(".");
 	}
-	TRACE("realpath id %u path %s", id, path);
+	debug3("request %u: realpath", id);
+	verbose("realpath \"%s\"", path);
 	if (realpath(path, resolvedname) == NULL) {
 		send_status(id, errno_to_portable(errno));
 	} else {
@@ -835,15 +981,36 @@
 	id = get_int();
 	oldpath = get_string(NULL);
 	newpath = get_string(NULL);
-	TRACE("rename id %u old %s new %s", id, oldpath, newpath);
+	debug3("request %u: rename", id);
+	logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
 	status = SSH2_FX_FAILURE;
 	if (lstat(oldpath, &sb) == -1)
 		status = errno_to_portable(errno);
 	else if (S_ISREG(sb.st_mode)) {
 		/* Race-free rename of regular files */
-		if (link(oldpath, newpath) == -1)
-			status = errno_to_portable(errno);
-		else if (unlink(oldpath) == -1) {
+		if (link(oldpath, newpath) == -1) {
+			if (errno == EOPNOTSUPP
+#ifdef LINK_OPNOTSUPP_ERRNO
+			    || errno == LINK_OPNOTSUPP_ERRNO
+#endif
+			    ) {
+				struct stat st;
+
+				/*
+				 * fs doesn't support links, so fall back to
+				 * stat+rename.  This is racy.
+				 */
+				if (stat(newpath, &st) == -1) {
+					if (rename(oldpath, newpath) == -1)
+						status =
+						    errno_to_portable(errno);
+					else
+						status = SSH2_FX_OK;
+				}
+			} else {
+				status = errno_to_portable(errno);
+			}
+		} else if (unlink(oldpath) == -1) {
 			status = errno_to_portable(errno);
 			/* clean spare link */
 			unlink(newpath);
@@ -865,20 +1032,21 @@
 {
 	u_int32_t id;
 	int len;
-	char link[MAXPATHLEN];
+	char buf[MAXPATHLEN];
 	char *path;
 
 	id = get_int();
 	path = get_string(NULL);
-	TRACE("readlink id %u path %s", id, path);
-	if ((len = readlink(path, link, sizeof(link) - 1)) == -1)
+	debug3("request %u: readlink", id);
+	verbose("readlink \"%s\"", path);
+	if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
 		send_status(id, errno_to_portable(errno));
 	else {
 		Stat s;
 
-		link[len] = '\0';
+		buf[len] = '\0';
 		attrib_clear(&s.attrib);
-		s.name = s.long_name = link;
+		s.name = s.long_name = buf;
 		send_names(id, 1, &s);
 	}
 	xfree(path);
@@ -894,7 +1062,8 @@
 	id = get_int();
 	oldpath = get_string(NULL);
 	newpath = get_string(NULL);
-	TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
+	debug3("request %u: symlink", id);
+	logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
 	/* this will fail if 'newpath' exists */
 	ret = symlink(oldpath, newpath);
 	status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
@@ -930,10 +1099,11 @@
 	if (buf_len < 5)
 		return;		/* Incomplete message. */
 	cp = buffer_ptr(&iqueue);
-	msg_len = GET_32BIT(cp);
-	if (msg_len > 256 * 1024) {
-		error("bad message ");
-		exit(11);
+	msg_len = get_u32(cp);
+	if (msg_len > SFTP_MAX_MSG_LENGTH) {
+		error("bad message from %s local user %s",
+		    client_addr, pw->pw_name);
+		cleanup_exit(11);
 	}
 	if (buf_len < msg_len + 4)
 		return;
@@ -1007,7 +1177,7 @@
 	}
 	/* discard the remaining bytes from the current packet */
 	if (buf_len < buffer_len(&iqueue))
-		fatal("iqueue grows");
+		fatal("iqueue grew unexpectedly");
 	consumed = buf_len - buffer_len(&iqueue);
 	if (msg_len < consumed)
 		fatal("msg_len %d < consumed %d", msg_len, consumed);
@@ -1015,56 +1185,93 @@
 		buffer_consume(&iqueue, msg_len - consumed);
 }
 
-#ifdef CHROOT
+/* Cleanup handler that logs active handles upon normal exit */
 void
-chroot_init(void)
+cleanup_exit(int i)
 {
-	char *user_dir, *new_root;
-
-	user_dir = getenv("HOME");
-	if (!user_dir)
-		fatal("HOME isn't in environment");
-
-	new_root = user_dir + 1;
-
-	while ((new_root = strchr(new_root, '.')) != NULL) {
-		new_root--;
-		if (strncmp(new_root, "/./", 3) == 0) {
-			*new_root = '\0';
-			new_root += 2;
-			
-			if (chroot(user_dir) != 0)
-				fatal("Couldn't chroot to user directory %s: %s", user_dir, strerror(errno));
-			
-			setenv("HOME", new_root, 1);
-			break;
-		}
-		new_root += 2;
+	if (pw != NULL && client_addr != NULL) {
+		handle_log_exit();
+		logit("session closed for local user %s from [%s]",
+		    pw->pw_name, client_addr);
 	}
+	_exit(i);
+}
+
+static void
+usage(void)
+{
+	extern char *__progname;
+
+	fprintf(stderr,
+	    "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
+	exit(1);
 }
-#endif /* CHROOT */
 
 int
-main(int ac, char **av)
+main(int argc, char **argv)
 {
 	fd_set *rset, *wset;
-	int in, out, max;
+	int in, out, max, ch, skipargs = 0, log_stderr = 0;
 	ssize_t len, olen, set_size;
+	SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
+	char *cp, buf[4*4096];
 
-	/* XXX should use getopt */
+	extern char *optarg;
+	extern char *__progname;
 
-	__progname = ssh_get_progname(av[0]);
-	handle_init();
+	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+	sanitise_stdfd();
 
-#ifdef DEBUG_SFTP_SERVER
-	log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
-#endif
+	__progname = ssh_get_progname(argv[0]);
+	log_init(__progname, log_level, log_facility, log_stderr);
+
+	while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
+		switch (ch) {
+		case 'c':
+			/*
+			 * Ignore all arguments if we are invoked as a
+			 * shell using "sftp-server -c command"
+			 */
+			skipargs = 1;
+			break;
+		case 'e':
+			log_stderr = 1;
+			break;
+		case 'l':
+			log_level = log_level_number(optarg);
+			if (log_level == SYSLOG_LEVEL_NOT_SET)
+				error("Invalid log level \"%s\"", optarg);
+			break;
+		case 'f':
+			log_facility = log_facility_number(optarg);
+			if (log_level == SYSLOG_FACILITY_NOT_SET)
+				error("Invalid log facility \"%s\"", optarg);
+			break;
+		case 'h':
+		default:
+			usage();
+		}
+	}
 
-#ifdef CHROOT
-	chroot_init();
-#endif
-	if (setuid(getuid()) != 0)
-		fatal("Couldn't drop privileges: %s", strerror(errno));
+	log_init(__progname, log_level, log_facility, log_stderr);
+
+	if ((cp = getenv("SSH_CONNECTION")) != NULL) {
+		client_addr = xstrdup(cp);
+		if ((cp = strchr(client_addr, ' ')) == NULL)
+			fatal("Malformed SSH_CONNECTION variable: \"%s\"",
+			    getenv("SSH_CONNECTION"));
+		*cp = '\0';
+	} else
+		client_addr = xstrdup("UNKNOWN");
+
+	if ((pw = getpwuid(getuid())) == NULL)
+		fatal("No user found for uid %lu", (u_long)getuid());
+	pw = pwcopy(pw);
+
+	logit("session opened for local user %s from [%s]",
+	    pw->pw_name, client_addr);
+
+	handle_init();
 
 	in = dup(STDIN_FILENO);
 	out = dup(STDOUT_FILENO);
@@ -1091,7 +1298,15 @@
 		memset(rset, 0, set_size);
 		memset(wset, 0, set_size);
 
-		FD_SET(in, rset);
+		/*
+		 * Ensure that we can read a full buffer and handle
+		 * the worst-case length packet it can generate,
+		 * otherwise apply backpressure by stopping reads.
+		 */
+		if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
+		    buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
+			FD_SET(in, rset);
+
 		olen = buffer_len(&oqueue);
 		if (olen > 0)
 			FD_SET(out, wset);
@@ -1099,19 +1314,19 @@
 		if (select(max+1, rset, wset, NULL, NULL) < 0) {
 			if (errno == EINTR)
 				continue;
-			exit(2);
+			error("select: %s", strerror(errno));
+			cleanup_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);
+				cleanup_exit(0);
 			} else if (len < 0) {
-				error("read error");
-				exit(1);
+				error("read: %s", strerror(errno));
+				cleanup_exit(1);
 			} else {
 				buffer_append(&iqueue, buf, len);
 			}
@@ -1120,13 +1335,19 @@
 		if (FD_ISSET(out, wset)) {
 			len = write(out, buffer_ptr(&oqueue), olen);
 			if (len < 0) {
-				error("write error");
-				exit(1);
+				error("write: %s", strerror(errno));
+				cleanup_exit(1);
 			} else {
 				buffer_consume(&oqueue, len);
 			}
 		}
-		/* process requests from client */
-		process();
+
+		/*
+		 * Process requests from client if we can fit the results
+		 * into the output buffer, otherwise stop processing input
+		 * and let the output queue drain.
+		 */
+		if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
+			process();
 	}
 }

Youez - 2016 - github.com/yon3zu
LinuXploit