X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/799ae497fc1f308e76517858d866bdd27b56cdd8..22ce3a3becb01f9487f7fa12b859100c162e231c:/openssh/sftp-server.c diff --git a/openssh/sftp-server.c b/openssh/sftp-server.c index 64777be..2ef9753 100644 --- a/openssh/sftp-server.c +++ b/openssh/sftp-server.c @@ -1,46 +1,34 @@ -/* $OpenBSD: sftp-server.c,v 1.71 2007/01/03 07:22:36 stevesk Exp $ */ /* - * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * 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. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * 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.30 2001/07/31 12:42:50 jakob Exp $"); -#include -#include -#include -#ifdef HAVE_SYS_TIME_H -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xmalloc.h" #include "buffer.h" +#include "bufaux.h" +#include "getput.h" #include "log.h" -#include "misc.h" -#include "uidswap.h" +#include "xmalloc.h" #include "sftp.h" #include "sftp-common.h" @@ -49,13 +37,13 @@ #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 -/* Our verbosity */ -LogLevel log_level = SYSLOG_LEVEL_ERROR; - -/* Our client */ -struct passwd *pw = NULL; -char *client_addr = NULL; +#ifdef HAVE___PROGNAME +extern char *__progname; +#else +char *__progname; +#endif /* input and output queue */ Buffer iqueue; @@ -64,7 +52,7 @@ Buffer oqueue; /* Version of client */ int version; -/* portable attributes, etc. */ +/* portable attibutes, etc. */ typedef struct Stat Stat; @@ -127,33 +115,6 @@ flags_from_portable(int pflags) 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) { @@ -168,7 +129,6 @@ struct Handle { DIR *dirp; int fd; char *name; - u_int64_t bytes_read, bytes_write; }; enum { @@ -182,24 +142,23 @@ Handle handles[100]; static void handle_init(void) { - u_int i; + int i; - for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) + for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) handles[i].use = HANDLE_UNUSED; } static int -handle_new(int use, const char *name, int fd, DIR *dirp) +handle_new(int use, char *name, int fd, DIR *dirp) { - u_int i; + int i; - for (i = 0; i < sizeof(handles)/sizeof(Handle); 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 = xstrdup(name); - handles[i].bytes_read = handles[i].bytes_write = 0; + handles[i].name = name; return i; } } @@ -209,7 +168,7 @@ handle_new(int use, const char *name, int fd, DIR *dirp) static int handle_is_ok(int i, int type) { - return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) && + return i >= 0 && i < sizeof(handles)/sizeof(Handle) && handles[i].use == type; } @@ -219,19 +178,19 @@ handle_to_string(int handle, char **stringp, int *hlenp) if (stringp == NULL || hlenp == NULL) return -1; *stringp = xmalloc(sizeof(int32_t)); - put_u32(*stringp, handle); + PUT_32BIT(*stringp, handle); *hlenp = sizeof(int32_t); return 0; } static int -handle_from_string(const char *handle, u_int hlen) +handle_from_string(char *handle, u_int hlen) { int val; if (hlen != sizeof(int32_t)) return -1; - val = get_u32(handle); + val = GET_32BIT(handle); if (handle_is_ok(val, HANDLE_FILE) || handle_is_ok(val, HANDLE_DIR)) return val; @@ -263,36 +222,6 @@ handle_to_fd(int handle) 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) { @@ -301,42 +230,15 @@ handle_close(int handle) if (handle_is_ok(handle, HANDLE_FILE)) { ret = close(handles[handle].fd); handles[handle].use = HANDLE_UNUSED; - xfree(handles[handle].name); } else if (handle_is_ok(handle, HANDLE_DIR)) { ret = closedir(handles[handle].dirp); handles[handle].use = HANDLE_UNUSED; - xfree(handles[handle].name); } else { errno = ENOENT; } 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), - handle_bytes_read(handle), 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) { @@ -363,9 +265,10 @@ send_msg(Buffer *m) buffer_consume(m, mlen); } -static const char * -status_to_message(u_int32_t status) +static void +send_status(u_int32_t id, u_int32_t error) { + Buffer msg; const char *status_messages[] = { "Success", /* SSH_FX_OK */ "End of file", /* SSH_FX_EOF */ @@ -378,31 +281,22 @@ status_to_message(u_int32_t status) "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; - - 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)); + TRACE("sent status id %d error %d", id, error); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_STATUS); buffer_put_int(&msg, id); - buffer_put_int(&msg, status); + buffer_put_int(&msg, error); if (version >= 3) { - buffer_put_cstring(&msg, status_to_message(status)); + buffer_put_cstring(&msg, + status_messages[MIN(error,SSH2_FX_MAX)]); buffer_put_cstring(&msg, ""); } send_msg(&msg); buffer_free(&msg); } static void -send_data_or_handle(char type, u_int32_t id, const char *data, int dlen) +send_data_or_handle(char type, u_int32_t id, char *data, int dlen) { Buffer msg; @@ -415,9 +309,9 @@ send_data_or_handle(char type, u_int32_t id, const char *data, int dlen) } static void -send_data(u_int32_t id, const char *data, int dlen) +send_data(u_int32_t id, char *data, int dlen) { - debug("request %u: sent data len %d", id, dlen); + TRACE("sent data id %d len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); } @@ -428,13 +322,13 @@ send_handle(u_int32_t id, int handle) int hlen; handle_to_string(handle, &string, &hlen); - debug("request %u: sent handle handle %d", id, handle); + TRACE("sent handle id %d handle %d", id, handle); send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); xfree(string); } static void -send_names(u_int32_t id, int count, const Stat *stats) +send_names(u_int32_t id, int count, Stat *stats) { Buffer msg; int i; @@ -443,7 +337,7 @@ send_names(u_int32_t id, int count, const Stat *stats) buffer_put_char(&msg, SSH2_FXP_NAME); buffer_put_int(&msg, id); buffer_put_int(&msg, count); - debug("request %u: sent names count %d", id, 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); @@ -454,11 +348,11 @@ send_names(u_int32_t id, int count, const Stat *stats) } static void -send_attrib(u_int32_t id, const Attrib *a) +send_attrib(u_int32_t id, Attrib *a) { Buffer msg; - debug("request %u: sent attrib have 0x%x", id, a->flags); + TRACE("sent attrib id %d have 0x%x", id, a->flags); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_ATTRS); buffer_put_int(&msg, id); @@ -474,8 +368,8 @@ process_init(void) { Buffer msg; - version = get_int(); - verbose("received client version %d", version); + version = buffer_get_int(&iqueue); + TRACE("client version %d", version); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_VERSION); buffer_put_int(&msg, SSH2_FILEXFER_VERSION); @@ -494,17 +388,15 @@ process_open(void) 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; - logit("open \"%s\" flags %s mode 0%o", - name, string_from_portable(pflags), mode); + 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, name, fd, NULL); + handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL); if (handle < 0) { close(fd); } else { @@ -525,8 +417,7 @@ process_close(void) id = get_int(); handle = get_handle(); - debug3("request %u: close handle %u", id, handle); - handle_log_close(handle, NULL); + TRACE("close id %d handle %d", id, handle); ret = handle_close(handle); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -545,11 +436,11 @@ process_read(void) off = get_int64(); len = get_int(); - debug("request %u: read \"%s\" (handle %d) off %llu len %d", - id, handle_to_name(handle), handle, (unsigned long long)off, len); + TRACE("read id %d handle %d off %llu len %d", id, handle, + (u_int64_t)off, len); if (len > sizeof buf) { len = sizeof buf; - debug2("read change len %d", len); + log("read change len %d", len); } fd = handle_to_fd(handle); if (fd >= 0) { @@ -565,7 +456,6 @@ process_read(void) } else { send_data(id, buf, ret); status = SSH2_FX_OK; - handle_update_read(handle, ret); } } } @@ -587,8 +477,8 @@ process_write(void) off = get_int64(); data = get_string(&len); - debug("request %u: write \"%s\" (handle %d) off %llu len %d", - id, handle_to_name(handle), handle, (unsigned long long)off, len); + TRACE("write id %d handle %d off %llu len %d", id, handle, + (u_int64_t)off, len); fd = handle_to_fd(handle); if (fd >= 0) { if (lseek(fd, off, SEEK_SET) < 0) { @@ -597,14 +487,13 @@ process_write(void) } else { /* XXX ATOMICIO ? */ ret = write(fd, data, len); - if (ret < 0) { + if (ret == -1) { error("process_write: write failed"); status = errno_to_portable(errno); - } else if ((size_t)ret == len) { + } else if (ret == len) { status = SSH2_FX_OK; - handle_update_write(handle, ret); } else { - debug2("nothing at all written"); + log("nothing at all written"); } } } @@ -623,8 +512,7 @@ process_do_stat(int do_lstat) id = get_int(); name = get_string(NULL); - debug3("request %u: %sstat", id, do_lstat ? "l" : ""); - verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name); + 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); @@ -660,10 +548,9 @@ process_fstat(void) id = get_int(); handle = get_handle(); - debug("request %u: fstat \"%s\" (handle %u)", - id, handle_to_name(handle), handle); + TRACE("fstat id %d handle %d", id, handle); fd = handle_to_fd(handle); - if (fd >= 0) { + if (fd >= 0) { ret = fstat(fd, &st); if (ret < 0) { status = errno_to_portable(errno); @@ -678,7 +565,7 @@ process_fstat(void) } static struct timeval * -attrib_to_tv(const Attrib *a) +attrib_to_tv(Attrib *a) { static struct timeval tv[2]; @@ -695,38 +582,24 @@ process_setstat(void) Attrib *a; u_int32_t id; char *name; - int status = SSH2_FX_OK, ret; + int ret; + int status = SSH2_FX_OK; id = get_int(); name = get_string(NULL); a = get_attrib(); - debug("request %u: setstat name \"%s\"", id, name); - if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { - logit("set \"%s\" size %llu", name, a->size); - ret = truncate(name, a->size); - if (ret == -1) - status = errno_to_portable(errno); - } + TRACE("setstat id %d name %s", id, name); 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); @@ -742,25 +615,18 @@ process_fsetstat(void) u_int32_t id; int handle, fd, ret; int status = SSH2_FX_OK; + char *name; id = get_int(); handle = get_handle(); a = get_attrib(); - debug("request %u: fsetstat handle %d", id, handle); + TRACE("fsetstat id %d handle %d", id, handle); fd = handle_to_fd(handle); - if (fd < 0) { + name = handle_to_name(handle); + if (fd < 0 || name == NULL) { status = SSH2_FX_FAILURE; } else { - char *name = handle_to_name(handle); - - if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { - logit("set \"%s\" size %llu", name, 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 @@ -770,12 +636,6 @@ process_fsetstat(void) 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 @@ -785,8 +645,6 @@ process_fsetstat(void) 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 @@ -809,13 +667,12 @@ process_opendir(void) id = get_int(); path = get_string(NULL); - debug3("request %u: opendir", id); - logit("opendir \"%s\"", path); + 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, path, 0, dirp); + handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); if (handle < 0) { closedir(dirp); } else { @@ -829,6 +686,48 @@ process_opendir(void) xfree(path); } +/* + * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh + */ +static char * +ls_file(char *name, struct stat *st) +{ + int ulen, glen, sz = 0; + struct passwd *pw; + struct group *gr; + struct tm *ltime = localtime(&st->st_mtime); + char *user, *group; + char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; + + strmode(st->st_mode, mode); + if ((pw = getpwuid(st->st_uid)) != NULL) { + user = pw->pw_name; + } else { + snprintf(ubuf, sizeof ubuf, "%d", st->st_uid); + user = ubuf; + } + if ((gr = getgrgid(st->st_gid)) != NULL) { + group = gr->gr_name; + } else { + snprintf(gbuf, sizeof gbuf, "%d", st->st_gid); + group = gbuf; + } + if (ltime != NULL) { + if (time(NULL) - st->st_mtime < (365*24*60*60)/2) + sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); + else + sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); + } + if (sz == 0) + tbuf[0] = '\0'; + ulen = MAX(strlen(user), 8); + glen = MAX(strlen(group), 8); + snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode, + st->st_nlink, ulen, user, glen, group, + (u_int64_t)st->st_size, tbuf, name); + return xstrdup(buf); +} + static void process_readdir(void) { @@ -840,23 +739,21 @@ process_readdir(void) id = get_int(); handle = get_handle(); - debug("request %u: readdir \"%s\" (handle %d)", id, - handle_to_name(handle), 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, SSH2_FX_FAILURE); } else { struct stat st; - char pathname[MAXPATHLEN]; + char pathname[1024]; Stat *stats; int nstats = 10, count = 0, i; - - stats = xcalloc(nstats, sizeof(Stat)); + stats = xmalloc(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, @@ -865,7 +762,7 @@ process_readdir(void) continue; stat_to_attrib(&st, &(stats[count].attrib)); stats[count].name = xstrdup(dp->d_name); - stats[count].long_name = ls_file(dp->d_name, &st, 0); + stats[count].long_name = ls_file(dp->d_name, &st); count++; /* send up to 100 entries in one message */ /* XXX check packet size instead */ @@ -874,7 +771,7 @@ process_readdir(void) } if (count > 0) { send_names(id, count, stats); - for (i = 0; i < count; i++) { + for(i = 0; i < count; i++) { xfree(stats[i].name); xfree(stats[i].long_name); } @@ -895,8 +792,7 @@ process_remove(void) id = get_int(); name = get_string(NULL); - debug3("request %u: remove", id); - logit("remove name \"%s\"", name); + TRACE("remove id %d name %s", id, name); ret = unlink(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -916,8 +812,7 @@ process_mkdir(void) a = get_attrib(); mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm & 0777 : 0777; - debug3("request %u: mkdir", id); - logit("mkdir name \"%s\" mode 0%o", name, mode); + TRACE("mkdir id %d name %s mode 0%o", id, name, mode); ret = mkdir(name, mode); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -933,8 +828,7 @@ process_rmdir(void) id = get_int(); name = get_string(NULL); - debug3("request %u: rmdir", id); - logit("rmdir name \"%s\"", name); + TRACE("rmdir id %d name %s", id, name); ret = rmdir(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); @@ -954,8 +848,7 @@ process_realpath(void) xfree(path); path = xstrdup("."); } - debug3("request %u: realpath", id); - verbose("realpath \"%s\"", path); + TRACE("realpath id %d path %s", id, path); if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { @@ -971,53 +864,18 @@ static void process_rename(void) { u_int32_t id; + struct stat st; char *oldpath, *newpath; - int status; - struct stat sb; + int ret, status = SSH2_FX_FAILURE; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); - 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) { - 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); - } else - status = SSH2_FX_OK; - } else if (stat(newpath, &sb) == -1) { - if (rename(oldpath, newpath) == -1) - status = errno_to_portable(errno); - else - status = SSH2_FX_OK; + TRACE("rename id %d old %s new %s", id, oldpath, newpath); + /* fail if 'newpath' exists */ + if (stat(newpath, &st) == -1) { + ret = rename(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; } send_status(id, status); xfree(oldpath); @@ -1029,21 +887,20 @@ process_readlink(void) { u_int32_t id; int len; - char buf[MAXPATHLEN]; + char link[MAXPATHLEN]; char *path; id = get_int(); path = get_string(NULL); - debug3("request %u: readlink", id); - verbose("readlink \"%s\"", path); - if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) + TRACE("readlink id %d path %s", id, path); + if ((len = readlink(path, link, sizeof(link) - 1)) == -1) send_status(id, errno_to_portable(errno)); else { Stat s; - - buf[len] = '\0'; + + link[len] = '\0'; attrib_clear(&s.attrib); - s.name = s.long_name = buf; + s.name = s.long_name = link; send_names(id, 1, &s); } xfree(path); @@ -1053,17 +910,19 @@ static void process_symlink(void) { u_int32_t id; + struct stat st; char *oldpath, *newpath; - int ret, status; + int ret, status = SSH2_FX_FAILURE; id = get_int(); oldpath = get_string(NULL); newpath = get_string(NULL); - 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; + TRACE("symlink id %d old %s new %s", id, oldpath, newpath); + /* fail if 'newpath' exists */ + if (stat(newpath, &st) == -1) { + ret = symlink(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(oldpath); xfree(newpath); @@ -1087,25 +946,20 @@ static void process(void) { u_int msg_len; - u_int buf_len; - u_int consumed; u_int type; u_char *cp; - buf_len = buffer_len(&iqueue); - if (buf_len < 5) + if (buffer_len(&iqueue) < 5) return; /* Incomplete message. */ - cp = buffer_ptr(&iqueue); - 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); + cp = (u_char *) buffer_ptr(&iqueue); + msg_len = GET_32BIT(cp); + if (msg_len > 256 * 1024) { + error("bad message "); + exit(11); } - if (buf_len < msg_len + 4) + if (buffer_len(&iqueue) < msg_len + 4) return; buffer_consume(&iqueue, 4); - buf_len -= 4; type = buffer_get_char(&iqueue); switch (type) { case SSH2_FXP_INIT: @@ -1172,104 +1026,24 @@ process(void) error("Unknown message %d", type); break; } - /* discard the remaining bytes from the current packet */ - if (buf_len < buffer_len(&iqueue)) - fatal("iqueue grew unexpectedly"); - consumed = buf_len - buffer_len(&iqueue); - if (msg_len < consumed) - fatal("msg_len %d < consumed %d", msg_len, consumed); - if (msg_len > consumed) - buffer_consume(&iqueue, msg_len - consumed); -} - -/* Cleanup handler that logs active handles upon normal exit */ -void -cleanup_exit(int i) -{ - 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); } int -main(int argc, char **argv) +main(int ac, char **av) { fd_set *rset, *wset; - int in, out, max, ch, skipargs = 0, log_stderr = 0; + int in, out, max; ssize_t len, olen, set_size; - SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; - char *cp; - - extern char *optarg; - extern char *__progname; - - /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ - sanitise_stdfd(); - - __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(); - } - } - - 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); + /* XXX should use getopt */ + __progname = get_progname(av[0]); handle_init(); +#ifdef DEBUG_SFTP_SERVER + log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); +#endif + in = dup(STDIN_FILENO); out = dup(STDOUT_FILENO); @@ -1303,8 +1077,7 @@ main(int argc, char **argv) if (select(max+1, rset, wset, NULL, NULL) < 0) { if (errno == EINTR) continue; - error("select: %s", strerror(errno)); - cleanup_exit(2); + exit(2); } /* copy stdin to iqueue */ @@ -1313,10 +1086,10 @@ main(int argc, char **argv) len = read(in, buf, sizeof buf); if (len == 0) { debug("read eof"); - cleanup_exit(0); + exit(0); } else if (len < 0) { - error("read: %s", strerror(errno)); - cleanup_exit(1); + error("read error"); + exit(1); } else { buffer_append(&iqueue, buf, len); } @@ -1325,8 +1098,8 @@ main(int argc, char **argv) if (FD_ISSET(out, wset)) { len = write(out, buffer_ptr(&oqueue), olen); if (len < 0) { - error("write: %s", strerror(errno)); - cleanup_exit(1); + error("write error"); + exit(1); } else { buffer_consume(&oqueue, len); }