[BACK]Return to sftp-server.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/sftp-server.c, Revision 1.102

1.102   ! djm         1: /* $OpenBSD: sftp-server.c,v 1.101 2013/10/14 23:28:23 djm Exp $ */
1.1       markus      2: /*
1.45      markus      3:  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
1.1       markus      4:  *
1.45      markus      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       markus      8:  *
1.45      markus      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       markus     16:  */
1.52      stevesk    17:
                     18: #include <sys/types.h>
                     19: #include <sys/stat.h>
1.66      stevesk    20: #include <sys/time.h>
1.67      stevesk    21: #include <sys/param.h>
1.79      djm        22: #include <sys/mount.h>
                     23: #include <sys/statvfs.h>
1.51      stevesk    24:
                     25: #include <dirent.h>
1.62      stevesk    26: #include <errno.h>
1.59      stevesk    27: #include <fcntl.h>
1.68      stevesk    28: #include <stdlib.h>
1.69      stevesk    29: #include <stdio.h>
1.65      stevesk    30: #include <string.h>
1.70      deraadt    31: #include <pwd.h>
1.64      stevesk    32: #include <time.h>
1.63      stevesk    33: #include <unistd.h>
1.70      deraadt    34: #include <stdarg.h>
1.1       markus     35:
1.70      deraadt    36: #include "xmalloc.h"
1.1       markus     37: #include "buffer.h"
1.14      markus     38: #include "log.h"
1.49      djm        39: #include "misc.h"
1.98      djm        40: #include "match.h"
1.58      djm        41: #include "uidswap.h"
1.1       markus     42:
1.10      markus     43: #include "sftp.h"
1.15      djm        44: #include "sftp-common.h"
1.1       markus     45:
                     46: /* helper */
1.10      markus     47: #define get_int64()                    buffer_get_int64(&iqueue);
1.1       markus     48: #define get_int()                      buffer_get_int(&iqueue);
                     49: #define get_string(lenp)               buffer_get_string(&iqueue, lenp);
1.58      djm        50:
                     51: /* Our verbosity */
1.98      djm        52: static LogLevel log_level = SYSLOG_LEVEL_ERROR;
1.58      djm        53:
                     54: /* Our client */
1.98      djm        55: static struct passwd *pw = NULL;
                     56: static char *client_addr = NULL;
1.1       markus     57:
                     58: /* input and output queue */
1.98      djm        59: static Buffer iqueue;
                     60: static Buffer oqueue;
1.1       markus     61:
1.23      djm        62: /* Version of client */
1.98      djm        63: static u_int version;
                     64:
                     65: /* SSH2_FXP_INIT received */
                     66: static int init_done;
1.23      djm        67:
1.90      djm        68: /* Disable writes */
1.98      djm        69: static int readonly;
                     70:
                     71: /* Requests that are allowed/denied */
                     72: static char *request_whitelist, *request_blacklist;
1.90      djm        73:
1.43      miod       74: /* portable attributes, etc. */
1.1       markus     75: typedef struct Stat Stat;
                     76:
1.15      djm        77: struct Stat {
1.1       markus     78:        char *name;
                     79:        char *long_name;
                     80:        Attrib attrib;
                     81: };
                     82:
1.98      djm        83: /* Packet handlers */
                     84: static void process_open(u_int32_t id);
                     85: static void process_close(u_int32_t id);
                     86: static void process_read(u_int32_t id);
                     87: static void process_write(u_int32_t id);
                     88: static void process_stat(u_int32_t id);
                     89: static void process_lstat(u_int32_t id);
                     90: static void process_fstat(u_int32_t id);
                     91: static void process_setstat(u_int32_t id);
                     92: static void process_fsetstat(u_int32_t id);
                     93: static void process_opendir(u_int32_t id);
                     94: static void process_readdir(u_int32_t id);
                     95: static void process_remove(u_int32_t id);
                     96: static void process_mkdir(u_int32_t id);
                     97: static void process_rmdir(u_int32_t id);
                     98: static void process_realpath(u_int32_t id);
                     99: static void process_rename(u_int32_t id);
                    100: static void process_readlink(u_int32_t id);
                    101: static void process_symlink(u_int32_t id);
                    102: static void process_extended_posix_rename(u_int32_t id);
                    103: static void process_extended_statvfs(u_int32_t id);
                    104: static void process_extended_fstatvfs(u_int32_t id);
                    105: static void process_extended_hardlink(u_int32_t id);
1.102   ! djm       106: static void process_extended_fsync(u_int32_t id);
1.98      djm       107: static void process_extended(u_int32_t id);
                    108:
                    109: struct sftp_handler {
                    110:        const char *name;       /* user-visible name for fine-grained perms */
                    111:        const char *ext_name;   /* extended request name */
                    112:        u_int type;             /* packet type, for non extended packets */
                    113:        void (*handler)(u_int32_t);
                    114:        int does_write;         /* if nonzero, banned for readonly mode */
                    115: };
                    116:
                    117: struct sftp_handler handlers[] = {
                    118:        /* NB. SSH2_FXP_OPEN does the readonly check in the handler itself */
                    119:        { "open", NULL, SSH2_FXP_OPEN, process_open, 0 },
                    120:        { "close", NULL, SSH2_FXP_CLOSE, process_close, 0 },
                    121:        { "read", NULL, SSH2_FXP_READ, process_read, 0 },
                    122:        { "write", NULL, SSH2_FXP_WRITE, process_write, 1 },
                    123:        { "lstat", NULL, SSH2_FXP_LSTAT, process_lstat, 0 },
                    124:        { "fstat", NULL, SSH2_FXP_FSTAT, process_fstat, 0 },
                    125:        { "setstat", NULL, SSH2_FXP_SETSTAT, process_setstat, 1 },
                    126:        { "fsetstat", NULL, SSH2_FXP_FSETSTAT, process_fsetstat, 1 },
                    127:        { "opendir", NULL, SSH2_FXP_OPENDIR, process_opendir, 0 },
                    128:        { "readdir", NULL, SSH2_FXP_READDIR, process_readdir, 0 },
                    129:        { "remove", NULL, SSH2_FXP_REMOVE, process_remove, 1 },
                    130:        { "mkdir", NULL, SSH2_FXP_MKDIR, process_mkdir, 1 },
                    131:        { "rmdir", NULL, SSH2_FXP_RMDIR, process_rmdir, 1 },
                    132:        { "realpath", NULL, SSH2_FXP_REALPATH, process_realpath, 0 },
                    133:        { "stat", NULL, SSH2_FXP_STAT, process_stat, 0 },
                    134:        { "rename", NULL, SSH2_FXP_RENAME, process_rename, 1 },
                    135:        { "readlink", NULL, SSH2_FXP_READLINK, process_readlink, 0 },
                    136:        { "symlink", NULL, SSH2_FXP_SYMLINK, process_symlink, 1 },
                    137:        { NULL, NULL, 0, NULL, 0 }
                    138: };
                    139:
                    140: /* SSH2_FXP_EXTENDED submessages */
                    141: struct sftp_handler extended_handlers[] = {
                    142:        { "posix-rename", "posix-rename@openssh.com", 0,
                    143:           process_extended_posix_rename, 1 },
                    144:        { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
                    145:        { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
                    146:        { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
1.102   ! djm       147:        { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
1.98      djm       148:        { NULL, NULL, 0, NULL, 0 }
                    149: };
                    150:
                    151: static int
                    152: request_permitted(struct sftp_handler *h)
                    153: {
                    154:        char *result;
                    155:
                    156:        if (readonly && h->does_write) {
                    157:                verbose("Refusing %s request in read-only mode", h->name);
                    158:                return 0;
                    159:        }
                    160:        if (request_blacklist != NULL &&
                    161:            ((result = match_list(h->name, request_blacklist, NULL))) != NULL) {
                    162:                free(result);
                    163:                verbose("Refusing blacklisted %s request", h->name);
                    164:                return 0;
                    165:        }
                    166:        if (request_whitelist != NULL &&
                    167:            ((result = match_list(h->name, request_whitelist, NULL))) != NULL) {
                    168:                free(result);
                    169:                debug2("Permitting whitelisted %s request", h->name);
                    170:                return 1;
                    171:        }
                    172:        if (request_whitelist != NULL) {
                    173:                verbose("Refusing non-whitelisted %s request", h->name);
                    174:                return 0;
                    175:        }
                    176:        return 1;
                    177: }
                    178:
1.28      itojun    179: static int
1.2       markus    180: errno_to_portable(int unixerrno)
1.1       markus    181: {
                    182:        int ret = 0;
1.22      deraadt   183:
1.2       markus    184:        switch (unixerrno) {
1.1       markus    185:        case 0:
1.10      markus    186:                ret = SSH2_FX_OK;
1.1       markus    187:                break;
                    188:        case ENOENT:
                    189:        case ENOTDIR:
                    190:        case EBADF:
                    191:        case ELOOP:
1.10      markus    192:                ret = SSH2_FX_NO_SUCH_FILE;
1.1       markus    193:                break;
                    194:        case EPERM:
                    195:        case EACCES:
                    196:        case EFAULT:
1.10      markus    197:                ret = SSH2_FX_PERMISSION_DENIED;
1.1       markus    198:                break;
                    199:        case ENAMETOOLONG:
                    200:        case EINVAL:
1.10      markus    201:                ret = SSH2_FX_BAD_MESSAGE;
1.82      dtucker   202:                break;
                    203:        case ENOSYS:
                    204:                ret = SSH2_FX_OP_UNSUPPORTED;
1.1       markus    205:                break;
                    206:        default:
1.10      markus    207:                ret = SSH2_FX_FAILURE;
1.1       markus    208:                break;
                    209:        }
                    210:        return ret;
                    211: }
                    212:
1.28      itojun    213: static int
1.1       markus    214: flags_from_portable(int pflags)
                    215: {
                    216:        int flags = 0;
1.22      deraadt   217:
1.20      deraadt   218:        if ((pflags & SSH2_FXF_READ) &&
                    219:            (pflags & SSH2_FXF_WRITE)) {
1.1       markus    220:                flags = O_RDWR;
1.10      markus    221:        } else if (pflags & SSH2_FXF_READ) {
1.1       markus    222:                flags = O_RDONLY;
1.10      markus    223:        } else if (pflags & SSH2_FXF_WRITE) {
1.1       markus    224:                flags = O_WRONLY;
                    225:        }
1.101     djm       226:        if (pflags & SSH2_FXF_APPEND)
                    227:                flags |= O_APPEND;
1.10      markus    228:        if (pflags & SSH2_FXF_CREAT)
1.1       markus    229:                flags |= O_CREAT;
1.10      markus    230:        if (pflags & SSH2_FXF_TRUNC)
1.1       markus    231:                flags |= O_TRUNC;
1.10      markus    232:        if (pflags & SSH2_FXF_EXCL)
1.1       markus    233:                flags |= O_EXCL;
                    234:        return flags;
                    235: }
                    236:
1.58      djm       237: static const char *
                    238: string_from_portable(int pflags)
                    239: {
                    240:        static char ret[128];
                    241:
                    242:        *ret = '\0';
                    243:
                    244: #define PAPPEND(str)   {                               \
                    245:                if (*ret != '\0')                       \
                    246:                        strlcat(ret, ",", sizeof(ret)); \
1.70      deraadt   247:                strlcat(ret, str, sizeof(ret));         \
1.58      djm       248:        }
                    249:
                    250:        if (pflags & SSH2_FXF_READ)
                    251:                PAPPEND("READ")
                    252:        if (pflags & SSH2_FXF_WRITE)
                    253:                PAPPEND("WRITE")
1.101     djm       254:        if (pflags & SSH2_FXF_APPEND)
                    255:                PAPPEND("APPEND")
1.58      djm       256:        if (pflags & SSH2_FXF_CREAT)
                    257:                PAPPEND("CREATE")
                    258:        if (pflags & SSH2_FXF_TRUNC)
                    259:                PAPPEND("TRUNCATE")
                    260:        if (pflags & SSH2_FXF_EXCL)
                    261:                PAPPEND("EXCL")
                    262:
                    263:        return ret;
                    264: }
                    265:
1.28      itojun    266: static Attrib *
1.1       markus    267: get_attrib(void)
                    268: {
                    269:        return decode_attrib(&iqueue);
                    270: }
                    271:
                    272: /* handle handles */
                    273:
                    274: typedef struct Handle Handle;
                    275: struct Handle {
                    276:        int use;
                    277:        DIR *dirp;
                    278:        int fd;
1.101     djm       279:        int flags;
1.1       markus    280:        char *name;
1.58      djm       281:        u_int64_t bytes_read, bytes_write;
1.75      djm       282:        int next_unused;
1.1       markus    283: };
1.22      deraadt   284:
1.1       markus    285: enum {
                    286:        HANDLE_UNUSED,
                    287:        HANDLE_DIR,
                    288:        HANDLE_FILE
                    289: };
1.22      deraadt   290:
1.75      djm       291: Handle *handles = NULL;
                    292: u_int num_handles = 0;
                    293: int first_unused_handle = -1;
                    294:
                    295: static void handle_unused(int i)
                    296: {
                    297:        handles[i].use = HANDLE_UNUSED;
                    298:        handles[i].next_unused = first_unused_handle;
                    299:        first_unused_handle = i;
1.1       markus    300: }
                    301:
1.28      itojun    302: static int
1.101     djm       303: handle_new(int use, const char *name, int fd, int flags, DIR *dirp)
1.1       markus    304: {
1.75      djm       305:        int i;
                    306:
                    307:        if (first_unused_handle == -1) {
                    308:                if (num_handles + 1 <= num_handles)
                    309:                        return -1;
                    310:                num_handles++;
                    311:                handles = xrealloc(handles, num_handles, sizeof(Handle));
                    312:                handle_unused(num_handles - 1);
                    313:        }
                    314:
                    315:        i = first_unused_handle;
                    316:        first_unused_handle = handles[i].next_unused;
                    317:
                    318:        handles[i].use = use;
                    319:        handles[i].dirp = dirp;
                    320:        handles[i].fd = fd;
1.101     djm       321:        handles[i].flags = flags;
1.75      djm       322:        handles[i].name = xstrdup(name);
                    323:        handles[i].bytes_read = handles[i].bytes_write = 0;
1.22      deraadt   324:
1.75      djm       325:        return i;
1.1       markus    326: }
                    327:
1.28      itojun    328: static int
1.1       markus    329: handle_is_ok(int i, int type)
                    330: {
1.75      djm       331:        return i >= 0 && (u_int)i < num_handles && handles[i].use == type;
1.1       markus    332: }
                    333:
1.28      itojun    334: static int
1.1       markus    335: handle_to_string(int handle, char **stringp, int *hlenp)
                    336: {
                    337:        if (stringp == NULL || hlenp == NULL)
                    338:                return -1;
1.13      markus    339:        *stringp = xmalloc(sizeof(int32_t));
1.57      djm       340:        put_u32(*stringp, handle);
1.13      markus    341:        *hlenp = sizeof(int32_t);
1.1       markus    342:        return 0;
                    343: }
                    344:
1.28      itojun    345: static int
1.44      jakob     346: handle_from_string(const char *handle, u_int hlen)
1.1       markus    347: {
1.13      markus    348:        int val;
1.22      deraadt   349:
1.13      markus    350:        if (hlen != sizeof(int32_t))
1.1       markus    351:                return -1;
1.57      djm       352:        val = get_u32(handle);
1.1       markus    353:        if (handle_is_ok(val, HANDLE_FILE) ||
                    354:            handle_is_ok(val, HANDLE_DIR))
                    355:                return val;
                    356:        return -1;
                    357: }
                    358:
1.28      itojun    359: static char *
1.1       markus    360: handle_to_name(int handle)
                    361: {
                    362:        if (handle_is_ok(handle, HANDLE_DIR)||
                    363:            handle_is_ok(handle, HANDLE_FILE))
                    364:                return handles[handle].name;
                    365:        return NULL;
                    366: }
                    367:
1.28      itojun    368: static DIR *
1.1       markus    369: handle_to_dir(int handle)
                    370: {
                    371:        if (handle_is_ok(handle, HANDLE_DIR))
                    372:                return handles[handle].dirp;
                    373:        return NULL;
                    374: }
                    375:
1.28      itojun    376: static int
1.1       markus    377: handle_to_fd(int handle)
                    378: {
1.17      stevesk   379:        if (handle_is_ok(handle, HANDLE_FILE))
1.1       markus    380:                return handles[handle].fd;
                    381:        return -1;
                    382: }
                    383:
1.101     djm       384: static int
                    385: handle_to_flags(int handle)
                    386: {
                    387:        if (handle_is_ok(handle, HANDLE_FILE))
                    388:                return handles[handle].flags;
                    389:        return 0;
                    390: }
                    391:
1.58      djm       392: static void
                    393: handle_update_read(int handle, ssize_t bytes)
                    394: {
                    395:        if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
                    396:                handles[handle].bytes_read += bytes;
                    397: }
                    398:
                    399: static void
                    400: handle_update_write(int handle, ssize_t bytes)
                    401: {
                    402:        if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
                    403:                handles[handle].bytes_write += bytes;
                    404: }
                    405:
                    406: static u_int64_t
                    407: handle_bytes_read(int handle)
                    408: {
                    409:        if (handle_is_ok(handle, HANDLE_FILE))
                    410:                return (handles[handle].bytes_read);
                    411:        return 0;
                    412: }
                    413:
                    414: static u_int64_t
                    415: handle_bytes_write(int handle)
                    416: {
                    417:        if (handle_is_ok(handle, HANDLE_FILE))
                    418:                return (handles[handle].bytes_write);
                    419:        return 0;
                    420: }
                    421:
1.28      itojun    422: static int
1.1       markus    423: handle_close(int handle)
                    424: {
                    425:        int ret = -1;
1.22      deraadt   426:
1.1       markus    427:        if (handle_is_ok(handle, HANDLE_FILE)) {
                    428:                ret = close(handles[handle].fd);
1.97      djm       429:                free(handles[handle].name);
1.75      djm       430:                handle_unused(handle);
1.1       markus    431:        } else if (handle_is_ok(handle, HANDLE_DIR)) {
                    432:                ret = closedir(handles[handle].dirp);
1.97      djm       433:                free(handles[handle].name);
1.75      djm       434:                handle_unused(handle);
1.1       markus    435:        } else {
                    436:                errno = ENOENT;
                    437:        }
                    438:        return ret;
                    439: }
                    440:
1.58      djm       441: static void
                    442: handle_log_close(int handle, char *emsg)
                    443: {
                    444:        if (handle_is_ok(handle, HANDLE_FILE)) {
                    445:                logit("%s%sclose \"%s\" bytes read %llu written %llu",
                    446:                    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
                    447:                    handle_to_name(handle),
1.72      stevesk   448:                    (unsigned long long)handle_bytes_read(handle),
                    449:                    (unsigned long long)handle_bytes_write(handle));
1.58      djm       450:        } else {
                    451:                logit("%s%sclosedir \"%s\"",
                    452:                    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
                    453:                    handle_to_name(handle));
                    454:        }
                    455: }
                    456:
                    457: static void
                    458: handle_log_exit(void)
                    459: {
                    460:        u_int i;
                    461:
1.75      djm       462:        for (i = 0; i < num_handles; i++)
1.58      djm       463:                if (handles[i].use != HANDLE_UNUSED)
                    464:                        handle_log_close(i, "forced");
                    465: }
                    466:
1.28      itojun    467: static int
1.1       markus    468: get_handle(void)
                    469: {
                    470:        char *handle;
1.10      markus    471:        int val = -1;
1.5       markus    472:        u_int hlen;
1.22      deraadt   473:
1.1       markus    474:        handle = get_string(&hlen);
1.10      markus    475:        if (hlen < 256)
                    476:                val = handle_from_string(handle, hlen);
1.97      djm       477:        free(handle);
1.1       markus    478:        return val;
                    479: }
                    480:
                    481: /* send replies */
                    482:
1.28      itojun    483: static void
1.1       markus    484: send_msg(Buffer *m)
                    485: {
                    486:        int mlen = buffer_len(m);
1.22      deraadt   487:
1.1       markus    488:        buffer_put_int(&oqueue, mlen);
                    489:        buffer_append(&oqueue, buffer_ptr(m), mlen);
                    490:        buffer_consume(m, mlen);
                    491: }
                    492:
1.58      djm       493: static const char *
                    494: status_to_message(u_int32_t status)
1.1       markus    495: {
1.23      djm       496:        const char *status_messages[] = {
                    497:                "Success",                      /* SSH_FX_OK */
                    498:                "End of file",                  /* SSH_FX_EOF */
                    499:                "No such file",                 /* SSH_FX_NO_SUCH_FILE */
                    500:                "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
                    501:                "Failure",                      /* SSH_FX_FAILURE */
                    502:                "Bad message",                  /* SSH_FX_BAD_MESSAGE */
                    503:                "No connection",                /* SSH_FX_NO_CONNECTION */
                    504:                "Connection lost",              /* SSH_FX_CONNECTION_LOST */
                    505:                "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
                    506:                "Unknown error"                 /* Others */
                    507:        };
1.58      djm       508:        return (status_messages[MIN(status,SSH2_FX_MAX)]);
                    509: }
1.22      deraadt   510:
1.58      djm       511: static void
                    512: send_status(u_int32_t id, u_int32_t status)
                    513: {
                    514:        Buffer msg;
                    515:
                    516:        debug3("request %u: sent status %u", id, status);
                    517:        if (log_level > SYSLOG_LEVEL_VERBOSE ||
                    518:            (status != SSH2_FX_OK && status != SSH2_FX_EOF))
                    519:                logit("sent status %s", status_to_message(status));
1.1       markus    520:        buffer_init(&msg);
1.10      markus    521:        buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1       markus    522:        buffer_put_int(&msg, id);
1.46      avsm      523:        buffer_put_int(&msg, status);
1.23      djm       524:        if (version >= 3) {
1.58      djm       525:                buffer_put_cstring(&msg, status_to_message(status));
1.23      djm       526:                buffer_put_cstring(&msg, "");
                    527:        }
1.1       markus    528:        send_msg(&msg);
                    529:        buffer_free(&msg);
                    530: }
1.28      itojun    531: static void
1.44      jakob     532: send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
1.1       markus    533: {
                    534:        Buffer msg;
1.22      deraadt   535:
1.1       markus    536:        buffer_init(&msg);
                    537:        buffer_put_char(&msg, type);
                    538:        buffer_put_int(&msg, id);
                    539:        buffer_put_string(&msg, data, dlen);
                    540:        send_msg(&msg);
                    541:        buffer_free(&msg);
                    542: }
                    543:
1.28      itojun    544: static void
1.44      jakob     545: send_data(u_int32_t id, const char *data, int dlen)
1.1       markus    546: {
1.58      djm       547:        debug("request %u: sent data len %d", id, dlen);
1.10      markus    548:        send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1       markus    549: }
                    550:
1.28      itojun    551: static void
1.1       markus    552: send_handle(u_int32_t id, int handle)
                    553: {
                    554:        char *string;
                    555:        int hlen;
1.22      deraadt   556:
1.1       markus    557:        handle_to_string(handle, &string, &hlen);
1.58      djm       558:        debug("request %u: sent handle handle %d", id, handle);
1.10      markus    559:        send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.97      djm       560:        free(string);
1.1       markus    561: }
                    562:
1.28      itojun    563: static void
1.44      jakob     564: send_names(u_int32_t id, int count, const Stat *stats)
1.1       markus    565: {
                    566:        Buffer msg;
                    567:        int i;
1.22      deraadt   568:
1.1       markus    569:        buffer_init(&msg);
1.10      markus    570:        buffer_put_char(&msg, SSH2_FXP_NAME);
1.1       markus    571:        buffer_put_int(&msg, id);
                    572:        buffer_put_int(&msg, count);
1.58      djm       573:        debug("request %u: sent names count %d", id, count);
1.1       markus    574:        for (i = 0; i < count; i++) {
                    575:                buffer_put_cstring(&msg, stats[i].name);
                    576:                buffer_put_cstring(&msg, stats[i].long_name);
                    577:                encode_attrib(&msg, &stats[i].attrib);
                    578:        }
                    579:        send_msg(&msg);
                    580:        buffer_free(&msg);
                    581: }
                    582:
1.28      itojun    583: static void
1.44      jakob     584: send_attrib(u_int32_t id, const Attrib *a)
1.1       markus    585: {
                    586:        Buffer msg;
1.22      deraadt   587:
1.58      djm       588:        debug("request %u: sent attrib have 0x%x", id, a->flags);
1.1       markus    589:        buffer_init(&msg);
1.10      markus    590:        buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1       markus    591:        buffer_put_int(&msg, id);
                    592:        encode_attrib(&msg, a);
                    593:        send_msg(&msg);
                    594:        buffer_free(&msg);
                    595: }
                    596:
1.79      djm       597: static void
                    598: send_statvfs(u_int32_t id, struct statvfs *st)
                    599: {
                    600:        Buffer msg;
                    601:        u_int64_t flag;
                    602:
                    603:        flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
                    604:        flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
                    605:
                    606:        buffer_init(&msg);
                    607:        buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
                    608:        buffer_put_int(&msg, id);
1.83      dtucker   609:        buffer_put_int64(&msg, st->f_bsize);
                    610:        buffer_put_int64(&msg, st->f_frsize);
1.79      djm       611:        buffer_put_int64(&msg, st->f_blocks);
                    612:        buffer_put_int64(&msg, st->f_bfree);
                    613:        buffer_put_int64(&msg, st->f_bavail);
                    614:        buffer_put_int64(&msg, st->f_files);
                    615:        buffer_put_int64(&msg, st->f_ffree);
                    616:        buffer_put_int64(&msg, st->f_favail);
1.81      djm       617:        buffer_put_int64(&msg, st->f_fsid);
1.83      dtucker   618:        buffer_put_int64(&msg, flag);
                    619:        buffer_put_int64(&msg, st->f_namemax);
1.79      djm       620:        send_msg(&msg);
                    621:        buffer_free(&msg);
                    622: }
                    623:
1.1       markus    624: /* parse incoming */
                    625:
1.28      itojun    626: static void
1.1       markus    627: process_init(void)
                    628: {
                    629:        Buffer msg;
                    630:
1.35      markus    631:        version = get_int();
1.94      djm       632:        verbose("received client version %u", version);
1.1       markus    633:        buffer_init(&msg);
1.10      markus    634:        buffer_put_char(&msg, SSH2_FXP_VERSION);
                    635:        buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.78      djm       636:        /* POSIX rename extension */
                    637:        buffer_put_cstring(&msg, "posix-rename@openssh.com");
                    638:        buffer_put_cstring(&msg, "1"); /* version */
1.80      djm       639:        /* statvfs extension */
1.79      djm       640:        buffer_put_cstring(&msg, "statvfs@openssh.com");
1.81      djm       641:        buffer_put_cstring(&msg, "2"); /* version */
1.80      djm       642:        /* fstatvfs extension */
1.79      djm       643:        buffer_put_cstring(&msg, "fstatvfs@openssh.com");
1.81      djm       644:        buffer_put_cstring(&msg, "2"); /* version */
1.93      djm       645:        /* hardlink extension */
                    646:        buffer_put_cstring(&msg, "hardlink@openssh.com");
                    647:        buffer_put_cstring(&msg, "1"); /* version */
1.102   ! djm       648:        /* fsync extension */
        !           649:        buffer_put_cstring(&msg, "fsync@openssh.com");
        !           650:        buffer_put_cstring(&msg, "1"); /* version */
1.1       markus    651:        send_msg(&msg);
                    652:        buffer_free(&msg);
                    653: }
                    654:
1.28      itojun    655: static void
1.98      djm       656: process_open(u_int32_t id)
1.1       markus    657: {
1.98      djm       658:        u_int32_t pflags;
1.1       markus    659:        Attrib *a;
                    660:        char *name;
1.10      markus    661:        int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1       markus    662:
                    663:        name = get_string(NULL);
1.10      markus    664:        pflags = get_int();             /* portable flags */
1.61      djm       665:        debug3("request %u: open flags %d", id, pflags);
1.1       markus    666:        a = get_attrib();
                    667:        flags = flags_from_portable(pflags);
1.10      markus    668:        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.58      djm       669:        logit("open \"%s\" flags %s mode 0%o",
                    670:            name, string_from_portable(pflags), mode);
1.90      djm       671:        if (readonly &&
1.98      djm       672:            ((flags & O_ACCMODE) == O_WRONLY ||
                    673:            (flags & O_ACCMODE) == O_RDWR)) {
                    674:                verbose("Refusing open request in read-only mode");
                    675:                status = SSH2_FX_PERMISSION_DENIED;
                    676:        } else {
1.90      djm       677:                fd = open(name, flags, mode);
                    678:                if (fd < 0) {
                    679:                        status = errno_to_portable(errno);
1.1       markus    680:                } else {
1.101     djm       681:                        handle = handle_new(HANDLE_FILE, name, fd, flags, NULL);
1.90      djm       682:                        if (handle < 0) {
                    683:                                close(fd);
                    684:                        } else {
                    685:                                send_handle(id, handle);
                    686:                                status = SSH2_FX_OK;
                    687:                        }
1.1       markus    688:                }
                    689:        }
1.10      markus    690:        if (status != SSH2_FX_OK)
1.1       markus    691:                send_status(id, status);
1.97      djm       692:        free(name);
1.1       markus    693: }
                    694:
1.28      itojun    695: static void
1.98      djm       696: process_close(u_int32_t id)
1.1       markus    697: {
1.10      markus    698:        int handle, ret, status = SSH2_FX_FAILURE;
1.1       markus    699:
                    700:        handle = get_handle();
1.58      djm       701:        debug3("request %u: close handle %u", id, handle);
                    702:        handle_log_close(handle, NULL);
1.1       markus    703:        ret = handle_close(handle);
1.10      markus    704:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    705:        send_status(id, status);
                    706: }
                    707:
1.28      itojun    708: static void
1.98      djm       709: process_read(u_int32_t id)
1.1       markus    710: {
                    711:        char buf[64*1024];
1.98      djm       712:        u_int32_t len;
1.10      markus    713:        int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1       markus    714:        u_int64_t off;
                    715:
                    716:        handle = get_handle();
1.10      markus    717:        off = get_int64();
1.1       markus    718:        len = get_int();
                    719:
1.58      djm       720:        debug("request %u: read \"%s\" (handle %d) off %llu len %d",
                    721:            id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1       markus    722:        if (len > sizeof buf) {
                    723:                len = sizeof buf;
1.58      djm       724:                debug2("read change len %d", len);
1.1       markus    725:        }
                    726:        fd = handle_to_fd(handle);
                    727:        if (fd >= 0) {
                    728:                if (lseek(fd, off, SEEK_SET) < 0) {
                    729:                        error("process_read: seek failed");
                    730:                        status = errno_to_portable(errno);
                    731:                } else {
                    732:                        ret = read(fd, buf, len);
                    733:                        if (ret < 0) {
                    734:                                status = errno_to_portable(errno);
                    735:                        } else if (ret == 0) {
1.10      markus    736:                                status = SSH2_FX_EOF;
1.1       markus    737:                        } else {
                    738:                                send_data(id, buf, ret);
1.10      markus    739:                                status = SSH2_FX_OK;
1.58      djm       740:                                handle_update_read(handle, ret);
1.1       markus    741:                        }
                    742:                }
                    743:        }
1.10      markus    744:        if (status != SSH2_FX_OK)
1.1       markus    745:                send_status(id, status);
                    746: }
                    747:
1.28      itojun    748: static void
1.98      djm       749: process_write(u_int32_t id)
1.1       markus    750: {
                    751:        u_int64_t off;
1.5       markus    752:        u_int len;
1.90      djm       753:        int handle, fd, ret, status;
1.1       markus    754:        char *data;
                    755:
                    756:        handle = get_handle();
1.10      markus    757:        off = get_int64();
1.1       markus    758:        data = get_string(&len);
                    759:
1.58      djm       760:        debug("request %u: write \"%s\" (handle %d) off %llu len %d",
                    761:            id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1       markus    762:        fd = handle_to_fd(handle);
1.90      djm       763:
                    764:        if (fd < 0)
                    765:                status = SSH2_FX_FAILURE;
                    766:        else {
1.101     djm       767:                if (!(handle_to_flags(handle) & O_APPEND) &&
                    768:                                lseek(fd, off, SEEK_SET) < 0) {
1.1       markus    769:                        status = errno_to_portable(errno);
                    770:                        error("process_write: seek failed");
                    771:                } else {
                    772: /* XXX ATOMICIO ? */
                    773:                        ret = write(fd, data, len);
1.48      djm       774:                        if (ret < 0) {
1.1       markus    775:                                error("process_write: write failed");
                    776:                                status = errno_to_portable(errno);
1.48      djm       777:                        } else if ((size_t)ret == len) {
1.10      markus    778:                                status = SSH2_FX_OK;
1.58      djm       779:                                handle_update_write(handle, ret);
1.1       markus    780:                        } else {
1.58      djm       781:                                debug2("nothing at all written");
1.90      djm       782:                                status = SSH2_FX_FAILURE;
1.1       markus    783:                        }
                    784:                }
                    785:        }
                    786:        send_status(id, status);
1.97      djm       787:        free(data);
1.1       markus    788: }
                    789:
1.28      itojun    790: static void
1.98      djm       791: process_do_stat(u_int32_t id, int do_lstat)
1.1       markus    792: {
1.13      markus    793:        Attrib a;
1.1       markus    794:        struct stat st;
                    795:        char *name;
1.10      markus    796:        int ret, status = SSH2_FX_FAILURE;
1.1       markus    797:
                    798:        name = get_string(NULL);
1.58      djm       799:        debug3("request %u: %sstat", id, do_lstat ? "l" : "");
                    800:        verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
1.1       markus    801:        ret = do_lstat ? lstat(name, &st) : stat(name, &st);
                    802:        if (ret < 0) {
                    803:                status = errno_to_portable(errno);
                    804:        } else {
1.13      markus    805:                stat_to_attrib(&st, &a);
                    806:                send_attrib(id, &a);
1.10      markus    807:                status = SSH2_FX_OK;
1.1       markus    808:        }
1.10      markus    809:        if (status != SSH2_FX_OK)
1.1       markus    810:                send_status(id, status);
1.97      djm       811:        free(name);
1.1       markus    812: }
                    813:
1.28      itojun    814: static void
1.98      djm       815: process_stat(u_int32_t id)
1.1       markus    816: {
1.98      djm       817:        process_do_stat(id, 0);
1.1       markus    818: }
                    819:
1.28      itojun    820: static void
1.98      djm       821: process_lstat(u_int32_t id)
1.1       markus    822: {
1.98      djm       823:        process_do_stat(id, 1);
1.1       markus    824: }
                    825:
1.28      itojun    826: static void
1.98      djm       827: process_fstat(u_int32_t id)
1.1       markus    828: {
1.13      markus    829:        Attrib a;
1.1       markus    830:        struct stat st;
1.10      markus    831:        int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1       markus    832:
                    833:        handle = get_handle();
1.58      djm       834:        debug("request %u: fstat \"%s\" (handle %u)",
                    835:            id, handle_to_name(handle), handle);
1.1       markus    836:        fd = handle_to_fd(handle);
1.71      stevesk   837:        if (fd >= 0) {
1.1       markus    838:                ret = fstat(fd, &st);
                    839:                if (ret < 0) {
                    840:                        status = errno_to_portable(errno);
                    841:                } else {
1.13      markus    842:                        stat_to_attrib(&st, &a);
                    843:                        send_attrib(id, &a);
1.10      markus    844:                        status = SSH2_FX_OK;
1.1       markus    845:                }
                    846:        }
1.10      markus    847:        if (status != SSH2_FX_OK)
1.1       markus    848:                send_status(id, status);
                    849: }
                    850:
1.28      itojun    851: static struct timeval *
1.44      jakob     852: attrib_to_tv(const Attrib *a)
1.1       markus    853: {
                    854:        static struct timeval tv[2];
1.22      deraadt   855:
1.1       markus    856:        tv[0].tv_sec = a->atime;
                    857:        tv[0].tv_usec = 0;
                    858:        tv[1].tv_sec = a->mtime;
                    859:        tv[1].tv_usec = 0;
                    860:        return tv;
                    861: }
                    862:
1.28      itojun    863: static void
1.98      djm       864: process_setstat(u_int32_t id)
1.1       markus    865: {
                    866:        Attrib *a;
                    867:        char *name;
1.36      deraadt   868:        int status = SSH2_FX_OK, ret;
1.1       markus    869:
                    870:        name = get_string(NULL);
                    871:        a = get_attrib();
1.58      djm       872:        debug("request %u: setstat name \"%s\"", id, name);
1.33      markus    873:        if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72      stevesk   874:                logit("set \"%s\" size %llu",
                    875:                    name, (unsigned long long)a->size);
1.33      markus    876:                ret = truncate(name, a->size);
                    877:                if (ret == -1)
                    878:                        status = errno_to_portable(errno);
                    879:        }
1.10      markus    880:        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58      djm       881:                logit("set \"%s\" mode %04o", name, a->perm);
1.84      djm       882:                ret = chmod(name, a->perm & 07777);
1.1       markus    883:                if (ret == -1)
                    884:                        status = errno_to_portable(errno);
                    885:        }
1.10      markus    886:        if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58      djm       887:                char buf[64];
                    888:                time_t t = a->mtime;
                    889:
                    890:                strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
                    891:                    localtime(&t));
                    892:                logit("set \"%s\" modtime %s", name, buf);
1.1       markus    893:                ret = utimes(name, attrib_to_tv(a));
                    894:                if (ret == -1)
                    895:                        status = errno_to_portable(errno);
                    896:        }
1.18      stevesk   897:        if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58      djm       898:                logit("set \"%s\" owner %lu group %lu", name,
                    899:                    (u_long)a->uid, (u_long)a->gid);
1.18      stevesk   900:                ret = chown(name, a->uid, a->gid);
                    901:                if (ret == -1)
                    902:                        status = errno_to_portable(errno);
                    903:        }
1.1       markus    904:        send_status(id, status);
1.97      djm       905:        free(name);
1.1       markus    906: }
                    907:
1.28      itojun    908: static void
1.98      djm       909: process_fsetstat(u_int32_t id)
1.1       markus    910: {
                    911:        Attrib *a;
                    912:        int handle, fd, ret;
1.10      markus    913:        int status = SSH2_FX_OK;
1.1       markus    914:
                    915:        handle = get_handle();
                    916:        a = get_attrib();
1.58      djm       917:        debug("request %u: fsetstat handle %d", id, handle);
1.1       markus    918:        fd = handle_to_fd(handle);
1.90      djm       919:        if (fd < 0)
1.10      markus    920:                status = SSH2_FX_FAILURE;
1.90      djm       921:        else {
1.58      djm       922:                char *name = handle_to_name(handle);
                    923:
1.33      markus    924:                if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.72      stevesk   925:                        logit("set \"%s\" size %llu",
                    926:                            name, (unsigned long long)a->size);
1.33      markus    927:                        ret = ftruncate(fd, a->size);
                    928:                        if (ret == -1)
                    929:                                status = errno_to_portable(errno);
                    930:                }
1.10      markus    931:                if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58      djm       932:                        logit("set \"%s\" mode %04o", name, a->perm);
1.84      djm       933:                        ret = fchmod(fd, a->perm & 07777);
1.1       markus    934:                        if (ret == -1)
                    935:                                status = errno_to_portable(errno);
                    936:                }
1.10      markus    937:                if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58      djm       938:                        char buf[64];
                    939:                        time_t t = a->mtime;
                    940:
                    941:                        strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
                    942:                            localtime(&t));
                    943:                        logit("set \"%s\" modtime %s", name, buf);
1.1       markus    944:                        ret = futimes(fd, attrib_to_tv(a));
1.18      stevesk   945:                        if (ret == -1)
                    946:                                status = errno_to_portable(errno);
                    947:                }
                    948:                if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58      djm       949:                        logit("set \"%s\" owner %lu group %lu", name,
                    950:                            (u_long)a->uid, (u_long)a->gid);
1.18      stevesk   951:                        ret = fchown(fd, a->uid, a->gid);
1.1       markus    952:                        if (ret == -1)
                    953:                                status = errno_to_portable(errno);
                    954:                }
                    955:        }
                    956:        send_status(id, status);
                    957: }
                    958:
1.28      itojun    959: static void
1.98      djm       960: process_opendir(u_int32_t id)
1.1       markus    961: {
                    962:        DIR *dirp = NULL;
                    963:        char *path;
1.10      markus    964:        int handle, status = SSH2_FX_FAILURE;
1.1       markus    965:
                    966:        path = get_string(NULL);
1.58      djm       967:        debug3("request %u: opendir", id);
                    968:        logit("opendir \"%s\"", path);
1.17      stevesk   969:        dirp = opendir(path);
1.1       markus    970:        if (dirp == NULL) {
                    971:                status = errno_to_portable(errno);
                    972:        } else {
1.101     djm       973:                handle = handle_new(HANDLE_DIR, path, 0, 0, dirp);
1.1       markus    974:                if (handle < 0) {
                    975:                        closedir(dirp);
                    976:                } else {
                    977:                        send_handle(id, handle);
1.10      markus    978:                        status = SSH2_FX_OK;
1.1       markus    979:                }
1.17      stevesk   980:
1.1       markus    981:        }
1.10      markus    982:        if (status != SSH2_FX_OK)
1.1       markus    983:                send_status(id, status);
1.97      djm       984:        free(path);
1.1       markus    985: }
                    986:
1.28      itojun    987: static void
1.98      djm       988: process_readdir(u_int32_t id)
1.1       markus    989: {
                    990:        DIR *dirp;
                    991:        struct dirent *dp;
                    992:        char *path;
                    993:        int handle;
                    994:
                    995:        handle = get_handle();
1.58      djm       996:        debug("request %u: readdir \"%s\" (handle %d)", id,
                    997:            handle_to_name(handle), handle);
1.1       markus    998:        dirp = handle_to_dir(handle);
                    999:        path = handle_to_name(handle);
                   1000:        if (dirp == NULL || path == NULL) {
1.10      markus   1001:                send_status(id, SSH2_FX_FAILURE);
1.1       markus   1002:        } else {
                   1003:                struct stat st;
1.58      djm      1004:                char pathname[MAXPATHLEN];
1.1       markus   1005:                Stat *stats;
                   1006:                int nstats = 10, count = 0, i;
1.36      deraadt  1007:
1.54      djm      1008:                stats = xcalloc(nstats, sizeof(Stat));
1.1       markus   1009:                while ((dp = readdir(dirp)) != NULL) {
                   1010:                        if (count >= nstats) {
                   1011:                                nstats *= 2;
1.55      djm      1012:                                stats = xrealloc(stats, nstats, sizeof(Stat));
1.1       markus   1013:                        }
                   1014: /* XXX OVERFLOW ? */
1.30      jakob    1015:                        snprintf(pathname, sizeof pathname, "%s%s%s", path,
                   1016:                            strcmp(path, "/") ? "/" : "", dp->d_name);
1.1       markus   1017:                        if (lstat(pathname, &st) < 0)
                   1018:                                continue;
1.13      markus   1019:                        stat_to_attrib(&st, &(stats[count].attrib));
1.1       markus   1020:                        stats[count].name = xstrdup(dp->d_name);
1.91      djm      1021:                        stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
1.1       markus   1022:                        count++;
                   1023:                        /* send up to 100 entries in one message */
1.11      markus   1024:                        /* XXX check packet size instead */
1.1       markus   1025:                        if (count == 100)
                   1026:                                break;
                   1027:                }
1.10      markus   1028:                if (count > 0) {
                   1029:                        send_names(id, count, stats);
1.31      deraadt  1030:                        for (i = 0; i < count; i++) {
1.97      djm      1031:                                free(stats[i].name);
                   1032:                                free(stats[i].long_name);
1.10      markus   1033:                        }
                   1034:                } else {
                   1035:                        send_status(id, SSH2_FX_EOF);
1.1       markus   1036:                }
1.97      djm      1037:                free(stats);
1.1       markus   1038:        }
                   1039: }
                   1040:
1.28      itojun   1041: static void
1.98      djm      1042: process_remove(u_int32_t id)
1.1       markus   1043: {
                   1044:        char *name;
1.10      markus   1045:        int status = SSH2_FX_FAILURE;
1.1       markus   1046:        int ret;
                   1047:
                   1048:        name = get_string(NULL);
1.58      djm      1049:        debug3("request %u: remove", id);
                   1050:        logit("remove name \"%s\"", name);
1.98      djm      1051:        ret = unlink(name);
                   1052:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus   1053:        send_status(id, status);
1.97      djm      1054:        free(name);
1.1       markus   1055: }
                   1056:
1.28      itojun   1057: static void
1.98      djm      1058: process_mkdir(u_int32_t id)
1.1       markus   1059: {
                   1060:        Attrib *a;
                   1061:        char *name;
1.10      markus   1062:        int ret, mode, status = SSH2_FX_FAILURE;
1.1       markus   1063:
                   1064:        name = get_string(NULL);
                   1065:        a = get_attrib();
1.10      markus   1066:        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
1.84      djm      1067:            a->perm & 07777 : 0777;
1.58      djm      1068:        debug3("request %u: mkdir", id);
                   1069:        logit("mkdir name \"%s\" mode 0%o", name, mode);
1.98      djm      1070:        ret = mkdir(name, mode);
                   1071:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus   1072:        send_status(id, status);
1.97      djm      1073:        free(name);
1.1       markus   1074: }
                   1075:
1.28      itojun   1076: static void
1.98      djm      1077: process_rmdir(u_int32_t id)
1.1       markus   1078: {
                   1079:        char *name;
                   1080:        int ret, status;
                   1081:
                   1082:        name = get_string(NULL);
1.58      djm      1083:        debug3("request %u: rmdir", id);
                   1084:        logit("rmdir name \"%s\"", name);
1.98      djm      1085:        ret = rmdir(name);
                   1086:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus   1087:        send_status(id, status);
1.97      djm      1088:        free(name);
1.1       markus   1089: }
                   1090:
1.28      itojun   1091: static void
1.98      djm      1092: process_realpath(u_int32_t id)
1.1       markus   1093: {
                   1094:        char resolvedname[MAXPATHLEN];
                   1095:        char *path;
                   1096:
                   1097:        path = get_string(NULL);
1.7       markus   1098:        if (path[0] == '\0') {
1.97      djm      1099:                free(path);
1.7       markus   1100:                path = xstrdup(".");
                   1101:        }
1.58      djm      1102:        debug3("request %u: realpath", id);
                   1103:        verbose("realpath \"%s\"", path);
1.1       markus   1104:        if (realpath(path, resolvedname) == NULL) {
                   1105:                send_status(id, errno_to_portable(errno));
                   1106:        } else {
                   1107:                Stat s;
                   1108:                attrib_clear(&s.attrib);
                   1109:                s.name = s.long_name = resolvedname;
                   1110:                send_names(id, 1, &s);
                   1111:        }
1.97      djm      1112:        free(path);
1.1       markus   1113: }
                   1114:
1.28      itojun   1115: static void
1.98      djm      1116: process_rename(u_int32_t id)
1.1       markus   1117: {
                   1118:        char *oldpath, *newpath;
1.39      markus   1119:        int status;
1.41      deraadt  1120:        struct stat sb;
1.1       markus   1121:
                   1122:        oldpath = get_string(NULL);
                   1123:        newpath = get_string(NULL);
1.58      djm      1124:        debug3("request %u: rename", id);
                   1125:        logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1.41      deraadt  1126:        status = SSH2_FX_FAILURE;
1.98      djm      1127:        if (lstat(oldpath, &sb) == -1)
1.39      markus   1128:                status = errno_to_portable(errno);
1.41      deraadt  1129:        else if (S_ISREG(sb.st_mode)) {
                   1130:                /* Race-free rename of regular files */
1.47      dtucker  1131:                if (link(oldpath, newpath) == -1) {
                   1132:                        if (errno == EOPNOTSUPP) {
                   1133:                                struct stat st;
                   1134:
                   1135:                                /*
                   1136:                                 * fs doesn't support links, so fall back to
                   1137:                                 * stat+rename.  This is racy.
                   1138:                                 */
                   1139:                                if (stat(newpath, &st) == -1) {
                   1140:                                        if (rename(oldpath, newpath) == -1)
                   1141:                                                status =
                   1142:                                                    errno_to_portable(errno);
                   1143:                                        else
                   1144:                                                status = SSH2_FX_OK;
                   1145:                                }
                   1146:                        } else {
                   1147:                                status = errno_to_portable(errno);
                   1148:                        }
                   1149:                } else if (unlink(oldpath) == -1) {
1.41      deraadt  1150:                        status = errno_to_portable(errno);
                   1151:                        /* clean spare link */
                   1152:                        unlink(newpath);
                   1153:                } else
                   1154:                        status = SSH2_FX_OK;
                   1155:        } else if (stat(newpath, &sb) == -1) {
                   1156:                if (rename(oldpath, newpath) == -1)
                   1157:                        status = errno_to_portable(errno);
                   1158:                else
                   1159:                        status = SSH2_FX_OK;
                   1160:        }
1.1       markus   1161:        send_status(id, status);
1.97      djm      1162:        free(oldpath);
                   1163:        free(newpath);
1.1       markus   1164: }
                   1165:
1.28      itojun   1166: static void
1.98      djm      1167: process_readlink(u_int32_t id)
1.23      djm      1168: {
1.26      markus   1169:        int len;
1.46      avsm     1170:        char buf[MAXPATHLEN];
1.23      djm      1171:        char *path;
                   1172:
                   1173:        path = get_string(NULL);
1.58      djm      1174:        debug3("request %u: readlink", id);
                   1175:        verbose("readlink \"%s\"", path);
1.46      avsm     1176:        if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23      djm      1177:                send_status(id, errno_to_portable(errno));
                   1178:        else {
                   1179:                Stat s;
1.31      deraadt  1180:
1.46      avsm     1181:                buf[len] = '\0';
1.23      djm      1182:                attrib_clear(&s.attrib);
1.46      avsm     1183:                s.name = s.long_name = buf;
1.23      djm      1184:                send_names(id, 1, &s);
                   1185:        }
1.97      djm      1186:        free(path);
1.23      djm      1187: }
                   1188:
1.28      itojun   1189: static void
1.98      djm      1190: process_symlink(u_int32_t id)
1.23      djm      1191: {
                   1192:        char *oldpath, *newpath;
1.39      markus   1193:        int ret, status;
1.23      djm      1194:
                   1195:        oldpath = get_string(NULL);
                   1196:        newpath = get_string(NULL);
1.58      djm      1197:        debug3("request %u: symlink", id);
                   1198:        logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1.39      markus   1199:        /* this will fail if 'newpath' exists */
1.98      djm      1200:        ret = symlink(oldpath, newpath);
                   1201:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23      djm      1202:        send_status(id, status);
1.97      djm      1203:        free(oldpath);
                   1204:        free(newpath);
1.23      djm      1205: }
                   1206:
1.28      itojun   1207: static void
1.78      djm      1208: process_extended_posix_rename(u_int32_t id)
                   1209: {
                   1210:        char *oldpath, *newpath;
1.90      djm      1211:        int ret, status;
1.78      djm      1212:
                   1213:        oldpath = get_string(NULL);
                   1214:        newpath = get_string(NULL);
                   1215:        debug3("request %u: posix-rename", id);
                   1216:        logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
1.98      djm      1217:        ret = rename(oldpath, newpath);
                   1218:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.90      djm      1219:        send_status(id, status);
1.97      djm      1220:        free(oldpath);
                   1221:        free(newpath);
1.78      djm      1222: }
                   1223:
                   1224: static void
1.79      djm      1225: process_extended_statvfs(u_int32_t id)
                   1226: {
                   1227:        char *path;
                   1228:        struct statvfs st;
                   1229:
                   1230:        path = get_string(NULL);
                   1231:        debug3("request %u: statfs", id);
                   1232:        logit("statfs \"%s\"", path);
                   1233:
                   1234:        if (statvfs(path, &st) != 0)
                   1235:                send_status(id, errno_to_portable(errno));
                   1236:        else
                   1237:                send_statvfs(id, &st);
1.97      djm      1238:         free(path);
1.79      djm      1239: }
                   1240:
                   1241: static void
                   1242: process_extended_fstatvfs(u_int32_t id)
                   1243: {
                   1244:        int handle, fd;
                   1245:        struct statvfs st;
                   1246:
                   1247:        handle = get_handle();
                   1248:        debug("request %u: fstatvfs \"%s\" (handle %u)",
                   1249:            id, handle_to_name(handle), handle);
                   1250:        if ((fd = handle_to_fd(handle)) < 0) {
                   1251:                send_status(id, SSH2_FX_FAILURE);
                   1252:                return;
                   1253:        }
                   1254:        if (fstatvfs(fd, &st) != 0)
                   1255:                send_status(id, errno_to_portable(errno));
                   1256:        else
                   1257:                send_statvfs(id, &st);
                   1258: }
                   1259:
                   1260: static void
1.93      djm      1261: process_extended_hardlink(u_int32_t id)
                   1262: {
                   1263:        char *oldpath, *newpath;
                   1264:        int ret, status;
                   1265:
                   1266:        oldpath = get_string(NULL);
                   1267:        newpath = get_string(NULL);
                   1268:        debug3("request %u: hardlink", id);
                   1269:        logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1.98      djm      1270:        ret = link(oldpath, newpath);
                   1271:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.93      djm      1272:        send_status(id, status);
1.97      djm      1273:        free(oldpath);
                   1274:        free(newpath);
1.102   ! djm      1275: }
        !          1276:
        !          1277: static void
        !          1278: process_extended_fsync(u_int32_t id)
        !          1279: {
        !          1280:        int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED;
        !          1281:
        !          1282:        handle = get_handle();
        !          1283:        debug3("request %u: fsync (handle %u)", id, handle);
        !          1284:        verbose("fsync \"%s\"", handle_to_name(handle));
        !          1285:        if ((fd = handle_to_fd(handle)) < 0)
        !          1286:                status = SSH2_FX_NO_SUCH_FILE;
        !          1287:        else if (handle_is_ok(handle, HANDLE_FILE)) {
        !          1288:                ret = fsync(fd);
        !          1289:                status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
        !          1290:        }
        !          1291:        send_status(id, status);
1.93      djm      1292: }
                   1293:
                   1294: static void
1.98      djm      1295: process_extended(u_int32_t id)
1.10      markus   1296: {
                   1297:        char *request;
1.98      djm      1298:        u_int i;
1.10      markus   1299:
                   1300:        request = get_string(NULL);
1.98      djm      1301:        for (i = 0; extended_handlers[i].handler != NULL; i++) {
                   1302:                if (strcmp(request, extended_handlers[i].ext_name) == 0) {
                   1303:                        if (!request_permitted(&extended_handlers[i]))
                   1304:                                send_status(id, SSH2_FX_PERMISSION_DENIED);
                   1305:                        else
                   1306:                                extended_handlers[i].handler(id);
                   1307:                        break;
                   1308:                }
                   1309:        }
                   1310:        if (extended_handlers[i].handler == NULL) {
                   1311:                error("Unknown extended request \"%.100s\"", request);
1.78      djm      1312:                send_status(id, SSH2_FX_OP_UNSUPPORTED);        /* MUST */
1.98      djm      1313:        }
1.97      djm      1314:        free(request);
1.10      markus   1315: }
1.1       markus   1316:
                   1317: /* stolen from ssh-agent */
                   1318:
1.28      itojun   1319: static void
1.1       markus   1320: process(void)
                   1321: {
1.98      djm      1322:        u_int msg_len, buf_len, consumed, type, i;
1.9       markus   1323:        u_char *cp;
1.98      djm      1324:        u_int32_t id;
1.1       markus   1325:
1.34      markus   1326:        buf_len = buffer_len(&iqueue);
                   1327:        if (buf_len < 5)
1.1       markus   1328:                return;         /* Incomplete message. */
1.32      stevesk  1329:        cp = buffer_ptr(&iqueue);
1.57      djm      1330:        msg_len = get_u32(cp);
1.50      djm      1331:        if (msg_len > SFTP_MAX_MSG_LENGTH) {
1.58      djm      1332:                error("bad message from %s local user %s",
                   1333:                    client_addr, pw->pw_name);
1.76      markus   1334:                sftp_server_cleanup_exit(11);
1.1       markus   1335:        }
1.34      markus   1336:        if (buf_len < msg_len + 4)
1.1       markus   1337:                return;
                   1338:        buffer_consume(&iqueue, 4);
1.34      markus   1339:        buf_len -= 4;
1.1       markus   1340:        type = buffer_get_char(&iqueue);
1.98      djm      1341:
1.1       markus   1342:        switch (type) {
1.10      markus   1343:        case SSH2_FXP_INIT:
1.1       markus   1344:                process_init();
1.98      djm      1345:                init_done = 1;
1.1       markus   1346:                break;
1.10      markus   1347:        case SSH2_FXP_EXTENDED:
1.98      djm      1348:                if (!init_done)
                   1349:                        fatal("Received extended request before init");
                   1350:                id = get_int();
                   1351:                process_extended(id);
1.10      markus   1352:                break;
1.1       markus   1353:        default:
1.98      djm      1354:                if (!init_done)
                   1355:                        fatal("Received %u request before init", type);
                   1356:                id = get_int();
                   1357:                for (i = 0; handlers[i].handler != NULL; i++) {
                   1358:                        if (type == handlers[i].type) {
                   1359:                                if (!request_permitted(&handlers[i])) {
                   1360:                                        send_status(id,
                   1361:                                            SSH2_FX_PERMISSION_DENIED);
                   1362:                                } else {
                   1363:                                        handlers[i].handler(id);
                   1364:                                }
                   1365:                                break;
                   1366:                        }
                   1367:                }
                   1368:                if (handlers[i].handler == NULL)
                   1369:                        error("Unknown message %u", type);
1.1       markus   1370:        }
1.34      markus   1371:        /* discard the remaining bytes from the current packet */
1.76      markus   1372:        if (buf_len < buffer_len(&iqueue)) {
                   1373:                error("iqueue grew unexpectedly");
                   1374:                sftp_server_cleanup_exit(255);
                   1375:        }
1.34      markus   1376:        consumed = buf_len - buffer_len(&iqueue);
1.76      markus   1377:        if (msg_len < consumed) {
1.98      djm      1378:                error("msg_len %u < consumed %u", msg_len, consumed);
1.76      markus   1379:                sftp_server_cleanup_exit(255);
                   1380:        }
1.34      markus   1381:        if (msg_len > consumed)
                   1382:                buffer_consume(&iqueue, msg_len - consumed);
1.1       markus   1383: }
                   1384:
1.58      djm      1385: /* Cleanup handler that logs active handles upon normal exit */
                   1386: void
1.76      markus   1387: sftp_server_cleanup_exit(int i)
1.58      djm      1388: {
                   1389:        if (pw != NULL && client_addr != NULL) {
                   1390:                handle_log_exit();
                   1391:                logit("session closed for local user %s from [%s]",
                   1392:                    pw->pw_name, client_addr);
                   1393:        }
                   1394:        _exit(i);
                   1395: }
                   1396:
                   1397: static void
1.76      markus   1398: sftp_server_usage(void)
1.58      djm      1399: {
                   1400:        extern char *__progname;
                   1401:
                   1402:        fprintf(stderr,
1.96      jmc      1403:            "usage: %s [-ehR] [-d start_directory] [-f log_facility] "
1.100     jmc      1404:            "[-l log_level]\n\t[-P blacklisted_requests] "
                   1405:            "[-p whitelisted_requests] [-u umask]\n"
                   1406:            "       %s -Q protocol_feature\n",
                   1407:            __progname, __progname);
1.58      djm      1408:        exit(1);
                   1409: }
                   1410:
1.1       markus   1411: int
1.77      djm      1412: sftp_server_main(int argc, char **argv, struct passwd *user_pw)
1.1       markus   1413: {
1.21      millert  1414:        fd_set *rset, *wset;
1.98      djm      1415:        int i, in, out, max, ch, skipargs = 0, log_stderr = 0;
1.21      millert  1416:        ssize_t len, olen, set_size;
1.58      djm      1417:        SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1.95      djm      1418:        char *cp, *homedir = NULL, buf[4*4096];
1.92      djm      1419:        long mask;
1.58      djm      1420:
                   1421:        extern char *optarg;
                   1422:        extern char *__progname;
1.49      djm      1423:
1.58      djm      1424:        log_init(__progname, log_level, log_facility, log_stderr);
                   1425:
1.95      djm      1426:        pw = pwcopy(user_pw);
                   1427:
1.98      djm      1428:        while (!skipargs && (ch = getopt(argc, argv,
                   1429:            "d:f:l:P:p:Q:u:cehR")) != -1) {
1.58      djm      1430:                switch (ch) {
1.98      djm      1431:                case 'Q':
                   1432:                        if (strcasecmp(optarg, "requests") != 0) {
                   1433:                                fprintf(stderr, "Invalid query type\n");
                   1434:                                exit(1);
                   1435:                        }
                   1436:                        for (i = 0; handlers[i].handler != NULL; i++)
                   1437:                                printf("%s\n", handlers[i].name);
                   1438:                        for (i = 0; extended_handlers[i].handler != NULL; i++)
                   1439:                                printf("%s\n", extended_handlers[i].name);
                   1440:                        exit(0);
                   1441:                        break;
1.90      djm      1442:                case 'R':
                   1443:                        readonly = 1;
                   1444:                        break;
1.58      djm      1445:                case 'c':
                   1446:                        /*
                   1447:                         * Ignore all arguments if we are invoked as a
1.70      deraadt  1448:                         * shell using "sftp-server -c command"
1.58      djm      1449:                         */
                   1450:                        skipargs = 1;
                   1451:                        break;
                   1452:                case 'e':
                   1453:                        log_stderr = 1;
                   1454:                        break;
                   1455:                case 'l':
                   1456:                        log_level = log_level_number(optarg);
                   1457:                        if (log_level == SYSLOG_LEVEL_NOT_SET)
                   1458:                                error("Invalid log level \"%s\"", optarg);
                   1459:                        break;
                   1460:                case 'f':
                   1461:                        log_facility = log_facility_number(optarg);
1.74      djm      1462:                        if (log_facility == SYSLOG_FACILITY_NOT_SET)
1.58      djm      1463:                                error("Invalid log facility \"%s\"", optarg);
1.86      djm      1464:                        break;
1.95      djm      1465:                case 'd':
                   1466:                        cp = tilde_expand_filename(optarg, user_pw->pw_uid);
                   1467:                        homedir = percent_expand(cp, "d", user_pw->pw_dir,
                   1468:                            "u", user_pw->pw_name, (char *)NULL);
                   1469:                        free(cp);
1.98      djm      1470:                        break;
                   1471:                case 'p':
                   1472:                        if (request_whitelist != NULL)
                   1473:                                fatal("Permitted requests already set");
                   1474:                        request_whitelist = xstrdup(optarg);
                   1475:                        break;
                   1476:                case 'P':
                   1477:                        if (request_blacklist != NULL)
                   1478:                                fatal("Refused requests already set");
                   1479:                        request_blacklist = xstrdup(optarg);
1.95      djm      1480:                        break;
1.86      djm      1481:                case 'u':
1.92      djm      1482:                        errno = 0;
                   1483:                        mask = strtol(optarg, &cp, 8);
                   1484:                        if (mask < 0 || mask > 0777 || *cp != '\0' ||
                   1485:                            cp == optarg || (mask == 0 && errno != 0))
                   1486:                                fatal("Invalid umask \"%s\"", optarg);
                   1487:                        (void)umask((mode_t)mask);
1.58      djm      1488:                        break;
                   1489:                case 'h':
                   1490:                default:
1.76      markus   1491:                        sftp_server_usage();
1.58      djm      1492:                }
                   1493:        }
                   1494:
                   1495:        log_init(__progname, log_level, log_facility, log_stderr);
                   1496:
                   1497:        if ((cp = getenv("SSH_CONNECTION")) != NULL) {
                   1498:                client_addr = xstrdup(cp);
1.76      markus   1499:                if ((cp = strchr(client_addr, ' ')) == NULL) {
                   1500:                        error("Malformed SSH_CONNECTION variable: \"%s\"",
1.58      djm      1501:                            getenv("SSH_CONNECTION"));
1.76      markus   1502:                        sftp_server_cleanup_exit(255);
                   1503:                }
1.58      djm      1504:                *cp = '\0';
                   1505:        } else
                   1506:                client_addr = xstrdup("UNKNOWN");
                   1507:
                   1508:        logit("session opened for local user %s from [%s]",
                   1509:            pw->pw_name, client_addr);
1.10      markus   1510:
1.89      djm      1511:        in = STDIN_FILENO;
                   1512:        out = STDOUT_FILENO;
1.1       markus   1513:
                   1514:        max = 0;
                   1515:        if (in > max)
                   1516:                max = in;
                   1517:        if (out > max)
                   1518:                max = out;
                   1519:
                   1520:        buffer_init(&iqueue);
                   1521:        buffer_init(&oqueue);
                   1522:
1.21      millert  1523:        set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
                   1524:        rset = (fd_set *)xmalloc(set_size);
                   1525:        wset = (fd_set *)xmalloc(set_size);
1.95      djm      1526:
                   1527:        if (homedir != NULL) {
                   1528:                if (chdir(homedir) != 0) {
                   1529:                        error("chdir to \"%s\" failed: %s", homedir,
                   1530:                            strerror(errno));
                   1531:                }
                   1532:        }
1.21      millert  1533:
1.1       markus   1534:        for (;;) {
1.21      millert  1535:                memset(rset, 0, set_size);
                   1536:                memset(wset, 0, set_size);
1.1       markus   1537:
1.73      djm      1538:                /*
                   1539:                 * Ensure that we can read a full buffer and handle
                   1540:                 * the worst-case length packet it can generate,
                   1541:                 * otherwise apply backpressure by stopping reads.
                   1542:                 */
                   1543:                if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
                   1544:                    buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
                   1545:                        FD_SET(in, rset);
                   1546:
1.1       markus   1547:                olen = buffer_len(&oqueue);
                   1548:                if (olen > 0)
1.21      millert  1549:                        FD_SET(out, wset);
1.1       markus   1550:
1.21      millert  1551:                if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1       markus   1552:                        if (errno == EINTR)
                   1553:                                continue;
1.58      djm      1554:                        error("select: %s", strerror(errno));
1.76      markus   1555:                        sftp_server_cleanup_exit(2);
1.1       markus   1556:                }
                   1557:
                   1558:                /* copy stdin to iqueue */
1.21      millert  1559:                if (FD_ISSET(in, rset)) {
1.1       markus   1560:                        len = read(in, buf, sizeof buf);
                   1561:                        if (len == 0) {
                   1562:                                debug("read eof");
1.76      markus   1563:                                sftp_server_cleanup_exit(0);
1.1       markus   1564:                        } else if (len < 0) {
1.58      djm      1565:                                error("read: %s", strerror(errno));
1.76      markus   1566:                                sftp_server_cleanup_exit(1);
1.1       markus   1567:                        } else {
                   1568:                                buffer_append(&iqueue, buf, len);
                   1569:                        }
                   1570:                }
                   1571:                /* send oqueue to stdout */
1.21      millert  1572:                if (FD_ISSET(out, wset)) {
1.1       markus   1573:                        len = write(out, buffer_ptr(&oqueue), olen);
                   1574:                        if (len < 0) {
1.58      djm      1575:                                error("write: %s", strerror(errno));
1.76      markus   1576:                                sftp_server_cleanup_exit(1);
1.1       markus   1577:                        } else {
                   1578:                                buffer_consume(&oqueue, len);
                   1579:                        }
                   1580:                }
1.73      djm      1581:
                   1582:                /*
                   1583:                 * Process requests from client if we can fit the results
                   1584:                 * into the output buffer, otherwise stop processing input
                   1585:                 * and let the output queue drain.
                   1586:                 */
                   1587:                if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
                   1588:                        process();
1.1       markus   1589:        }
                   1590: }