=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sftp-server.c,v retrieving revision 1.33.2.3 retrieving revision 1.34 diff -u -r1.33.2.3 -r1.34 --- src/usr.bin/ssh/sftp-server.c 2003/04/03 22:35:17 1.33.2.3 +++ src/usr.bin/ssh/sftp-server.c 2002/06/06 17:12:44 1.34 @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" -RCSID("$OpenBSD: sftp-server.c,v 1.33.2.3 2003/04/03 22:35:17 miod Exp $"); +RCSID("$OpenBSD: sftp-server.c,v 1.34 2002/06/06 17:12:44 markus Exp $"); #include "buffer.h" #include "bufaux.h" @@ -152,7 +152,7 @@ handles[i].use = use; handles[i].dirp = dirp; handles[i].fd = fd; - handles[i].name = xstrdup(name); + handles[i].name = name; return i; } } @@ -224,11 +224,9 @@ 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; } @@ -278,7 +276,7 @@ "Unknown error" /* Others */ }; - TRACE("sent status id %u error %u", id, error); + TRACE("sent status id %d error %d", id, error); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_STATUS); buffer_put_int(&msg, id); @@ -307,7 +305,7 @@ static void send_data(u_int32_t id, char *data, int dlen) { - TRACE("sent data id %u len %d", id, dlen); + TRACE("sent data id %d len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); } @@ -318,7 +316,7 @@ int hlen; handle_to_string(handle, &string, &hlen); - TRACE("sent handle id %u 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); } @@ -333,7 +331,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); + 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); @@ -348,7 +346,7 @@ { Buffer msg; - TRACE("sent attrib id %u 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); @@ -364,7 +362,7 @@ { Buffer msg; - version = get_int(); + version = buffer_get_int(&iqueue); TRACE("client version %d", version); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_VERSION); @@ -387,12 +385,12 @@ 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); + 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 { @@ -413,7 +411,7 @@ id = get_int(); handle = get_handle(); - TRACE("close id %u handle %d", id, handle); + 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); @@ -432,7 +430,7 @@ off = get_int64(); len = get_int(); - TRACE("read id %u handle %d off %llu len %d", id, handle, + TRACE("read id %d handle %d off %llu len %d", id, handle, (unsigned long long)off, len); if (len > sizeof buf) { len = sizeof buf; @@ -473,7 +471,7 @@ off = get_int64(); data = get_string(&len); - TRACE("write id %u handle %d off %llu len %d", id, handle, + TRACE("write id %d handle %d off %llu len %d", id, handle, (unsigned long long)off, len); fd = handle_to_fd(handle); if (fd >= 0) { @@ -508,7 +506,7 @@ id = get_int(); name = get_string(NULL); - TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, 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); @@ -544,7 +542,7 @@ id = get_int(); handle = get_handle(); - TRACE("fstat id %u handle %d", id, handle); + TRACE("fstat id %d handle %d", id, handle); fd = handle_to_fd(handle); if (fd >= 0) { ret = fstat(fd, &st); @@ -578,12 +576,13 @@ 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(); - TRACE("setstat id %u name %s", id, name); + TRACE("setstat id %d name %s", id, name); if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { ret = truncate(name, a->size); if (ret == -1) @@ -619,7 +618,7 @@ id = get_int(); handle = get_handle(); a = get_attrib(); - TRACE("fsetstat id %u handle %d", id, handle); + TRACE("fsetstat id %d handle %d", id, handle); fd = handle_to_fd(handle); if (fd < 0) { status = SSH2_FX_FAILURE; @@ -658,12 +657,12 @@ id = get_int(); path = get_string(NULL); - TRACE("opendir id %u path %s", id, 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 { @@ -677,6 +676,48 @@ 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, + (unsigned long long)st->st_size, tbuf, name); + return xstrdup(buf); +} + static void process_readdir(void) { @@ -688,7 +729,7 @@ id = get_int(); handle = get_handle(); - TRACE("readdir id %u handle %d", id, handle); + TRACE("readdir id %d handle %d", id, handle); dirp = handle_to_dir(handle); path = handle_to_name(handle); if (dirp == NULL || path == NULL) { @@ -698,7 +739,6 @@ char pathname[1024]; Stat *stats; int nstats = 10, count = 0, i; - stats = xmalloc(nstats * sizeof(Stat)); while ((dp = readdir(dirp)) != NULL) { if (count >= nstats) { @@ -712,7 +752,7 @@ 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 */ @@ -742,7 +782,7 @@ id = get_int(); name = get_string(NULL); - TRACE("remove id %u name %s", id, 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); @@ -762,7 +802,7 @@ 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); + 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); @@ -778,7 +818,7 @@ id = get_int(); name = get_string(NULL); - TRACE("rmdir id %u name %s", id, 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); @@ -798,7 +838,7 @@ xfree(path); path = xstrdup("."); } - TRACE("realpath id %u path %s", id, path); + TRACE("realpath id %d path %s", id, path); if (realpath(path, resolvedname) == NULL) { send_status(id, errno_to_portable(errno)); } else { @@ -814,32 +854,18 @@ 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); - TRACE("rename id %u old %s new %s", id, 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) { - 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); @@ -856,7 +882,7 @@ id = get_int(); path = get_string(NULL); - TRACE("readlink id %u path %s", id, path); + 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 { @@ -874,16 +900,19 @@ 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); - TRACE("symlink id %u old %s new %s", id, 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);