[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.58

1.58    ! djm         1: /* $OpenBSD: sftp-server.c,v 1.57 2006/03/30 09:58:16 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:  */
                     17: #include "includes.h"
1.52      stevesk    18:
                     19: #include <sys/types.h>
                     20: #include <sys/stat.h>
1.51      stevesk    21:
                     22: #include <dirent.h>
1.1       markus     23:
                     24: #include "buffer.h"
                     25: #include "bufaux.h"
1.14      markus     26: #include "log.h"
1.1       markus     27: #include "xmalloc.h"
1.49      djm        28: #include "misc.h"
1.58    ! djm        29: #include "uidswap.h"
1.1       markus     30:
1.10      markus     31: #include "sftp.h"
1.15      djm        32: #include "sftp-common.h"
1.1       markus     33:
                     34: /* helper */
1.10      markus     35: #define get_int64()                    buffer_get_int64(&iqueue);
1.1       markus     36: #define get_int()                      buffer_get_int(&iqueue);
                     37: #define get_string(lenp)               buffer_get_string(&iqueue, lenp);
1.58    ! djm        38:
        !            39: /* Our verbosity */
        !            40: LogLevel log_level = SYSLOG_LEVEL_ERROR;
        !            41:
        !            42: /* Our client */
        !            43: struct passwd *pw = NULL;
        !            44: char *client_addr = NULL;
1.1       markus     45:
                     46: /* input and output queue */
                     47: Buffer iqueue;
                     48: Buffer oqueue;
                     49:
1.23      djm        50: /* Version of client */
                     51: int version;
                     52:
1.43      miod       53: /* portable attributes, etc. */
1.1       markus     54:
                     55: typedef struct Stat Stat;
                     56:
1.15      djm        57: struct Stat {
1.1       markus     58:        char *name;
                     59:        char *long_name;
                     60:        Attrib attrib;
                     61: };
                     62:
1.28      itojun     63: static int
1.2       markus     64: errno_to_portable(int unixerrno)
1.1       markus     65: {
                     66:        int ret = 0;
1.22      deraadt    67:
1.2       markus     68:        switch (unixerrno) {
1.1       markus     69:        case 0:
1.10      markus     70:                ret = SSH2_FX_OK;
1.1       markus     71:                break;
                     72:        case ENOENT:
                     73:        case ENOTDIR:
                     74:        case EBADF:
                     75:        case ELOOP:
1.10      markus     76:                ret = SSH2_FX_NO_SUCH_FILE;
1.1       markus     77:                break;
                     78:        case EPERM:
                     79:        case EACCES:
                     80:        case EFAULT:
1.10      markus     81:                ret = SSH2_FX_PERMISSION_DENIED;
1.1       markus     82:                break;
                     83:        case ENAMETOOLONG:
                     84:        case EINVAL:
1.10      markus     85:                ret = SSH2_FX_BAD_MESSAGE;
1.1       markus     86:                break;
                     87:        default:
1.10      markus     88:                ret = SSH2_FX_FAILURE;
1.1       markus     89:                break;
                     90:        }
                     91:        return ret;
                     92: }
                     93:
1.28      itojun     94: static int
1.1       markus     95: flags_from_portable(int pflags)
                     96: {
                     97:        int flags = 0;
1.22      deraadt    98:
1.20      deraadt    99:        if ((pflags & SSH2_FXF_READ) &&
                    100:            (pflags & SSH2_FXF_WRITE)) {
1.1       markus    101:                flags = O_RDWR;
1.10      markus    102:        } else if (pflags & SSH2_FXF_READ) {
1.1       markus    103:                flags = O_RDONLY;
1.10      markus    104:        } else if (pflags & SSH2_FXF_WRITE) {
1.1       markus    105:                flags = O_WRONLY;
                    106:        }
1.10      markus    107:        if (pflags & SSH2_FXF_CREAT)
1.1       markus    108:                flags |= O_CREAT;
1.10      markus    109:        if (pflags & SSH2_FXF_TRUNC)
1.1       markus    110:                flags |= O_TRUNC;
1.10      markus    111:        if (pflags & SSH2_FXF_EXCL)
1.1       markus    112:                flags |= O_EXCL;
                    113:        return flags;
                    114: }
                    115:
1.58    ! djm       116: static const char *
        !           117: string_from_portable(int pflags)
        !           118: {
        !           119:        static char ret[128];
        !           120:
        !           121:        *ret = '\0';
        !           122:
        !           123: #define PAPPEND(str)   {                               \
        !           124:                if (*ret != '\0')                       \
        !           125:                        strlcat(ret, ",", sizeof(ret)); \
        !           126:                strlcat(ret, str, sizeof(ret));         \
        !           127:        }
        !           128:
        !           129:        if (pflags & SSH2_FXF_READ)
        !           130:                PAPPEND("READ")
        !           131:        if (pflags & SSH2_FXF_WRITE)
        !           132:                PAPPEND("WRITE")
        !           133:        if (pflags & SSH2_FXF_CREAT)
        !           134:                PAPPEND("CREATE")
        !           135:        if (pflags & SSH2_FXF_TRUNC)
        !           136:                PAPPEND("TRUNCATE")
        !           137:        if (pflags & SSH2_FXF_EXCL)
        !           138:                PAPPEND("EXCL")
        !           139:
        !           140:        return ret;
        !           141: }
        !           142:
1.28      itojun    143: static Attrib *
1.1       markus    144: get_attrib(void)
                    145: {
                    146:        return decode_attrib(&iqueue);
                    147: }
                    148:
                    149: /* handle handles */
                    150:
                    151: typedef struct Handle Handle;
                    152: struct Handle {
                    153:        int use;
                    154:        DIR *dirp;
                    155:        int fd;
                    156:        char *name;
1.58    ! djm       157:        u_int64_t bytes_read, bytes_write;
1.1       markus    158: };
1.22      deraadt   159:
1.1       markus    160: enum {
                    161:        HANDLE_UNUSED,
                    162:        HANDLE_DIR,
                    163:        HANDLE_FILE
                    164: };
1.22      deraadt   165:
1.1       markus    166: Handle handles[100];
                    167:
1.28      itojun    168: static void
1.1       markus    169: handle_init(void)
                    170: {
1.48      djm       171:        u_int i;
1.22      deraadt   172:
1.31      deraadt   173:        for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
1.1       markus    174:                handles[i].use = HANDLE_UNUSED;
                    175: }
                    176:
1.28      itojun    177: static int
1.44      jakob     178: handle_new(int use, const char *name, int fd, DIR *dirp)
1.1       markus    179: {
1.48      djm       180:        u_int i;
1.22      deraadt   181:
1.31      deraadt   182:        for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
1.1       markus    183:                if (handles[i].use == HANDLE_UNUSED) {
                    184:                        handles[i].use = use;
                    185:                        handles[i].dirp = dirp;
                    186:                        handles[i].fd = fd;
1.40      markus    187:                        handles[i].name = xstrdup(name);
1.58    ! djm       188:                        handles[i].bytes_read = handles[i].bytes_write = 0;
1.1       markus    189:                        return i;
                    190:                }
                    191:        }
                    192:        return -1;
                    193: }
                    194:
1.28      itojun    195: static int
1.1       markus    196: handle_is_ok(int i, int type)
                    197: {
1.48      djm       198:        return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
1.10      markus    199:            handles[i].use == type;
1.1       markus    200: }
                    201:
1.28      itojun    202: static int
1.1       markus    203: handle_to_string(int handle, char **stringp, int *hlenp)
                    204: {
                    205:        if (stringp == NULL || hlenp == NULL)
                    206:                return -1;
1.13      markus    207:        *stringp = xmalloc(sizeof(int32_t));
1.57      djm       208:        put_u32(*stringp, handle);
1.13      markus    209:        *hlenp = sizeof(int32_t);
1.1       markus    210:        return 0;
                    211: }
                    212:
1.28      itojun    213: static int
1.44      jakob     214: handle_from_string(const char *handle, u_int hlen)
1.1       markus    215: {
1.13      markus    216:        int val;
1.22      deraadt   217:
1.13      markus    218:        if (hlen != sizeof(int32_t))
1.1       markus    219:                return -1;
1.57      djm       220:        val = get_u32(handle);
1.1       markus    221:        if (handle_is_ok(val, HANDLE_FILE) ||
                    222:            handle_is_ok(val, HANDLE_DIR))
                    223:                return val;
                    224:        return -1;
                    225: }
                    226:
1.28      itojun    227: static char *
1.1       markus    228: handle_to_name(int handle)
                    229: {
                    230:        if (handle_is_ok(handle, HANDLE_DIR)||
                    231:            handle_is_ok(handle, HANDLE_FILE))
                    232:                return handles[handle].name;
                    233:        return NULL;
                    234: }
                    235:
1.28      itojun    236: static DIR *
1.1       markus    237: handle_to_dir(int handle)
                    238: {
                    239:        if (handle_is_ok(handle, HANDLE_DIR))
                    240:                return handles[handle].dirp;
                    241:        return NULL;
                    242: }
                    243:
1.28      itojun    244: static int
1.1       markus    245: handle_to_fd(int handle)
                    246: {
1.17      stevesk   247:        if (handle_is_ok(handle, HANDLE_FILE))
1.1       markus    248:                return handles[handle].fd;
                    249:        return -1;
                    250: }
                    251:
1.58    ! djm       252: static void
        !           253: handle_update_read(int handle, ssize_t bytes)
        !           254: {
        !           255:        if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
        !           256:                handles[handle].bytes_read += bytes;
        !           257: }
        !           258:
        !           259: static void
        !           260: handle_update_write(int handle, ssize_t bytes)
        !           261: {
        !           262:        if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
        !           263:                handles[handle].bytes_write += bytes;
        !           264: }
        !           265:
        !           266: static u_int64_t
        !           267: handle_bytes_read(int handle)
        !           268: {
        !           269:        if (handle_is_ok(handle, HANDLE_FILE))
        !           270:                return (handles[handle].bytes_read);
        !           271:        return 0;
        !           272: }
        !           273:
        !           274: static u_int64_t
        !           275: handle_bytes_write(int handle)
        !           276: {
        !           277:        if (handle_is_ok(handle, HANDLE_FILE))
        !           278:                return (handles[handle].bytes_write);
        !           279:        return 0;
        !           280: }
        !           281:
1.28      itojun    282: static int
1.1       markus    283: handle_close(int handle)
                    284: {
                    285:        int ret = -1;
1.22      deraadt   286:
1.1       markus    287:        if (handle_is_ok(handle, HANDLE_FILE)) {
                    288:                ret = close(handles[handle].fd);
                    289:                handles[handle].use = HANDLE_UNUSED;
1.40      markus    290:                xfree(handles[handle].name);
1.1       markus    291:        } else if (handle_is_ok(handle, HANDLE_DIR)) {
                    292:                ret = closedir(handles[handle].dirp);
                    293:                handles[handle].use = HANDLE_UNUSED;
1.40      markus    294:                xfree(handles[handle].name);
1.1       markus    295:        } else {
                    296:                errno = ENOENT;
                    297:        }
                    298:        return ret;
                    299: }
                    300:
1.58    ! djm       301: static void
        !           302: handle_log_close(int handle, char *emsg)
        !           303: {
        !           304:        if (handle_is_ok(handle, HANDLE_FILE)) {
        !           305:                logit("%s%sclose \"%s\" bytes read %llu written %llu",
        !           306:                    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
        !           307:                    handle_to_name(handle),
        !           308:                    handle_bytes_read(handle), handle_bytes_write(handle));
        !           309:        } else {
        !           310:                logit("%s%sclosedir \"%s\"",
        !           311:                    emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
        !           312:                    handle_to_name(handle));
        !           313:        }
        !           314: }
        !           315:
        !           316: static void
        !           317: handle_log_exit(void)
        !           318: {
        !           319:        u_int i;
        !           320:
        !           321:        for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
        !           322:                if (handles[i].use != HANDLE_UNUSED)
        !           323:                        handle_log_close(i, "forced");
        !           324: }
        !           325:
1.28      itojun    326: static int
1.1       markus    327: get_handle(void)
                    328: {
                    329:        char *handle;
1.10      markus    330:        int val = -1;
1.5       markus    331:        u_int hlen;
1.22      deraadt   332:
1.1       markus    333:        handle = get_string(&hlen);
1.10      markus    334:        if (hlen < 256)
                    335:                val = handle_from_string(handle, hlen);
1.1       markus    336:        xfree(handle);
                    337:        return val;
                    338: }
                    339:
                    340: /* send replies */
                    341:
1.28      itojun    342: static void
1.1       markus    343: send_msg(Buffer *m)
                    344: {
                    345:        int mlen = buffer_len(m);
1.22      deraadt   346:
1.1       markus    347:        buffer_put_int(&oqueue, mlen);
                    348:        buffer_append(&oqueue, buffer_ptr(m), mlen);
                    349:        buffer_consume(m, mlen);
                    350: }
                    351:
1.58    ! djm       352: static const char *
        !           353: status_to_message(u_int32_t status)
1.1       markus    354: {
1.23      djm       355:        const char *status_messages[] = {
                    356:                "Success",                      /* SSH_FX_OK */
                    357:                "End of file",                  /* SSH_FX_EOF */
                    358:                "No such file",                 /* SSH_FX_NO_SUCH_FILE */
                    359:                "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
                    360:                "Failure",                      /* SSH_FX_FAILURE */
                    361:                "Bad message",                  /* SSH_FX_BAD_MESSAGE */
                    362:                "No connection",                /* SSH_FX_NO_CONNECTION */
                    363:                "Connection lost",              /* SSH_FX_CONNECTION_LOST */
                    364:                "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
                    365:                "Unknown error"                 /* Others */
                    366:        };
1.58    ! djm       367:        return (status_messages[MIN(status,SSH2_FX_MAX)]);
        !           368: }
1.22      deraadt   369:
1.58    ! djm       370: static void
        !           371: send_status(u_int32_t id, u_int32_t status)
        !           372: {
        !           373:        Buffer msg;
        !           374:
        !           375:        debug3("request %u: sent status %u", id, status);
        !           376:        if (log_level > SYSLOG_LEVEL_VERBOSE ||
        !           377:            (status != SSH2_FX_OK && status != SSH2_FX_EOF))
        !           378:                logit("sent status %s", status_to_message(status));
1.1       markus    379:        buffer_init(&msg);
1.10      markus    380:        buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1       markus    381:        buffer_put_int(&msg, id);
1.46      avsm      382:        buffer_put_int(&msg, status);
1.23      djm       383:        if (version >= 3) {
1.58    ! djm       384:                buffer_put_cstring(&msg, status_to_message(status));
1.23      djm       385:                buffer_put_cstring(&msg, "");
                    386:        }
1.1       markus    387:        send_msg(&msg);
                    388:        buffer_free(&msg);
                    389: }
1.28      itojun    390: static void
1.44      jakob     391: send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
1.1       markus    392: {
                    393:        Buffer msg;
1.22      deraadt   394:
1.1       markus    395:        buffer_init(&msg);
                    396:        buffer_put_char(&msg, type);
                    397:        buffer_put_int(&msg, id);
                    398:        buffer_put_string(&msg, data, dlen);
                    399:        send_msg(&msg);
                    400:        buffer_free(&msg);
                    401: }
                    402:
1.28      itojun    403: static void
1.44      jakob     404: send_data(u_int32_t id, const char *data, int dlen)
1.1       markus    405: {
1.58    ! djm       406:        debug("request %u: sent data len %d", id, dlen);
1.10      markus    407:        send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1       markus    408: }
                    409:
1.28      itojun    410: static void
1.1       markus    411: send_handle(u_int32_t id, int handle)
                    412: {
                    413:        char *string;
                    414:        int hlen;
1.22      deraadt   415:
1.1       markus    416:        handle_to_string(handle, &string, &hlen);
1.58    ! djm       417:        debug("request %u: sent handle handle %d", id, handle);
1.10      markus    418:        send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1       markus    419:        xfree(string);
                    420: }
                    421:
1.28      itojun    422: static void
1.44      jakob     423: send_names(u_int32_t id, int count, const Stat *stats)
1.1       markus    424: {
                    425:        Buffer msg;
                    426:        int i;
1.22      deraadt   427:
1.1       markus    428:        buffer_init(&msg);
1.10      markus    429:        buffer_put_char(&msg, SSH2_FXP_NAME);
1.1       markus    430:        buffer_put_int(&msg, id);
                    431:        buffer_put_int(&msg, count);
1.58    ! djm       432:        debug("request %u: sent names count %d", id, count);
1.1       markus    433:        for (i = 0; i < count; i++) {
                    434:                buffer_put_cstring(&msg, stats[i].name);
                    435:                buffer_put_cstring(&msg, stats[i].long_name);
                    436:                encode_attrib(&msg, &stats[i].attrib);
                    437:        }
                    438:        send_msg(&msg);
                    439:        buffer_free(&msg);
                    440: }
                    441:
1.28      itojun    442: static void
1.44      jakob     443: send_attrib(u_int32_t id, const Attrib *a)
1.1       markus    444: {
                    445:        Buffer msg;
1.22      deraadt   446:
1.58    ! djm       447:        debug("request %u: sent attrib have 0x%x", id, a->flags);
1.1       markus    448:        buffer_init(&msg);
1.10      markus    449:        buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1       markus    450:        buffer_put_int(&msg, id);
                    451:        encode_attrib(&msg, a);
                    452:        send_msg(&msg);
                    453:        buffer_free(&msg);
                    454: }
                    455:
                    456: /* parse incoming */
                    457:
1.28      itojun    458: static void
1.1       markus    459: process_init(void)
                    460: {
                    461:        Buffer msg;
                    462:
1.35      markus    463:        version = get_int();
1.58    ! djm       464:        verbose("received client version %d", version);
1.1       markus    465:        buffer_init(&msg);
1.10      markus    466:        buffer_put_char(&msg, SSH2_FXP_VERSION);
                    467:        buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1       markus    468:        send_msg(&msg);
                    469:        buffer_free(&msg);
                    470: }
                    471:
1.28      itojun    472: static void
1.1       markus    473: process_open(void)
                    474: {
                    475:        u_int32_t id, pflags;
                    476:        Attrib *a;
                    477:        char *name;
1.10      markus    478:        int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1       markus    479:
                    480:        id = get_int();
1.58    ! djm       481:        debug3("request %u: open flags %d", id, pflags);
1.1       markus    482:        name = get_string(NULL);
1.10      markus    483:        pflags = get_int();             /* portable flags */
1.1       markus    484:        a = get_attrib();
                    485:        flags = flags_from_portable(pflags);
1.10      markus    486:        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.58    ! djm       487:        logit("open \"%s\" flags %s mode 0%o",
        !           488:            name, string_from_portable(pflags), mode);
1.1       markus    489:        fd = open(name, flags, mode);
                    490:        if (fd < 0) {
                    491:                status = errno_to_portable(errno);
                    492:        } else {
1.40      markus    493:                handle = handle_new(HANDLE_FILE, name, fd, NULL);
1.1       markus    494:                if (handle < 0) {
                    495:                        close(fd);
                    496:                } else {
                    497:                        send_handle(id, handle);
1.10      markus    498:                        status = SSH2_FX_OK;
1.1       markus    499:                }
                    500:        }
1.10      markus    501:        if (status != SSH2_FX_OK)
1.1       markus    502:                send_status(id, status);
                    503:        xfree(name);
                    504: }
                    505:
1.28      itojun    506: static void
1.1       markus    507: process_close(void)
                    508: {
                    509:        u_int32_t id;
1.10      markus    510:        int handle, ret, status = SSH2_FX_FAILURE;
1.1       markus    511:
                    512:        id = get_int();
                    513:        handle = get_handle();
1.58    ! djm       514:        debug3("request %u: close handle %u", id, handle);
        !           515:        handle_log_close(handle, NULL);
1.1       markus    516:        ret = handle_close(handle);
1.10      markus    517:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    518:        send_status(id, status);
                    519: }
                    520:
1.28      itojun    521: static void
1.1       markus    522: process_read(void)
                    523: {
                    524:        char buf[64*1024];
1.10      markus    525:        u_int32_t id, len;
                    526:        int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1       markus    527:        u_int64_t off;
                    528:
                    529:        id = get_int();
                    530:        handle = get_handle();
1.10      markus    531:        off = get_int64();
1.1       markus    532:        len = get_int();
                    533:
1.58    ! djm       534:        debug("request %u: read \"%s\" (handle %d) off %llu len %d",
        !           535:            id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1       markus    536:        if (len > sizeof buf) {
                    537:                len = sizeof buf;
1.58    ! djm       538:                debug2("read change len %d", len);
1.1       markus    539:        }
                    540:        fd = handle_to_fd(handle);
                    541:        if (fd >= 0) {
                    542:                if (lseek(fd, off, SEEK_SET) < 0) {
                    543:                        error("process_read: seek failed");
                    544:                        status = errno_to_portable(errno);
                    545:                } else {
                    546:                        ret = read(fd, buf, len);
                    547:                        if (ret < 0) {
                    548:                                status = errno_to_portable(errno);
                    549:                        } else if (ret == 0) {
1.10      markus    550:                                status = SSH2_FX_EOF;
1.1       markus    551:                        } else {
                    552:                                send_data(id, buf, ret);
1.10      markus    553:                                status = SSH2_FX_OK;
1.58    ! djm       554:                                handle_update_read(handle, ret);
1.1       markus    555:                        }
                    556:                }
                    557:        }
1.10      markus    558:        if (status != SSH2_FX_OK)
1.1       markus    559:                send_status(id, status);
                    560: }
                    561:
1.28      itojun    562: static void
1.1       markus    563: process_write(void)
                    564: {
1.10      markus    565:        u_int32_t id;
1.1       markus    566:        u_int64_t off;
1.5       markus    567:        u_int len;
1.10      markus    568:        int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1       markus    569:        char *data;
                    570:
                    571:        id = get_int();
                    572:        handle = get_handle();
1.10      markus    573:        off = get_int64();
1.1       markus    574:        data = get_string(&len);
                    575:
1.58    ! djm       576:        debug("request %u: write \"%s\" (handle %d) off %llu len %d",
        !           577:            id, handle_to_name(handle), handle, (unsigned long long)off, len);
1.1       markus    578:        fd = handle_to_fd(handle);
                    579:        if (fd >= 0) {
                    580:                if (lseek(fd, off, SEEK_SET) < 0) {
                    581:                        status = errno_to_portable(errno);
                    582:                        error("process_write: seek failed");
                    583:                } else {
                    584: /* XXX ATOMICIO ? */
                    585:                        ret = write(fd, data, len);
1.48      djm       586:                        if (ret < 0) {
1.1       markus    587:                                error("process_write: write failed");
                    588:                                status = errno_to_portable(errno);
1.48      djm       589:                        } else if ((size_t)ret == len) {
1.10      markus    590:                                status = SSH2_FX_OK;
1.58    ! djm       591:                                handle_update_write(handle, ret);
1.1       markus    592:                        } else {
1.58    ! djm       593:                                debug2("nothing at all written");
1.1       markus    594:                        }
                    595:                }
                    596:        }
                    597:        send_status(id, status);
                    598:        xfree(data);
                    599: }
                    600:
1.28      itojun    601: static void
1.1       markus    602: process_do_stat(int do_lstat)
                    603: {
1.13      markus    604:        Attrib a;
1.1       markus    605:        struct stat st;
                    606:        u_int32_t id;
                    607:        char *name;
1.10      markus    608:        int ret, status = SSH2_FX_FAILURE;
1.1       markus    609:
                    610:        id = get_int();
                    611:        name = get_string(NULL);
1.58    ! djm       612:        debug3("request %u: %sstat", id, do_lstat ? "l" : "");
        !           613:        verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
1.1       markus    614:        ret = do_lstat ? lstat(name, &st) : stat(name, &st);
                    615:        if (ret < 0) {
                    616:                status = errno_to_portable(errno);
                    617:        } else {
1.13      markus    618:                stat_to_attrib(&st, &a);
                    619:                send_attrib(id, &a);
1.10      markus    620:                status = SSH2_FX_OK;
1.1       markus    621:        }
1.10      markus    622:        if (status != SSH2_FX_OK)
1.1       markus    623:                send_status(id, status);
                    624:        xfree(name);
                    625: }
                    626:
1.28      itojun    627: static void
1.1       markus    628: process_stat(void)
                    629: {
                    630:        process_do_stat(0);
                    631: }
                    632:
1.28      itojun    633: static void
1.1       markus    634: process_lstat(void)
                    635: {
                    636:        process_do_stat(1);
                    637: }
                    638:
1.28      itojun    639: static void
1.1       markus    640: process_fstat(void)
                    641: {
1.13      markus    642:        Attrib a;
1.1       markus    643:        struct stat st;
                    644:        u_int32_t id;
1.10      markus    645:        int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1       markus    646:
                    647:        id = get_int();
                    648:        handle = get_handle();
1.58    ! djm       649:        debug("request %u: fstat \"%s\" (handle %u)",
        !           650:            id, handle_to_name(handle), handle);
1.1       markus    651:        fd = handle_to_fd(handle);
                    652:        if (fd  >= 0) {
                    653:                ret = fstat(fd, &st);
                    654:                if (ret < 0) {
                    655:                        status = errno_to_portable(errno);
                    656:                } else {
1.13      markus    657:                        stat_to_attrib(&st, &a);
                    658:                        send_attrib(id, &a);
1.10      markus    659:                        status = SSH2_FX_OK;
1.1       markus    660:                }
                    661:        }
1.10      markus    662:        if (status != SSH2_FX_OK)
1.1       markus    663:                send_status(id, status);
                    664: }
                    665:
1.28      itojun    666: static struct timeval *
1.44      jakob     667: attrib_to_tv(const Attrib *a)
1.1       markus    668: {
                    669:        static struct timeval tv[2];
1.22      deraadt   670:
1.1       markus    671:        tv[0].tv_sec = a->atime;
                    672:        tv[0].tv_usec = 0;
                    673:        tv[1].tv_sec = a->mtime;
                    674:        tv[1].tv_usec = 0;
                    675:        return tv;
                    676: }
                    677:
1.28      itojun    678: static void
1.1       markus    679: process_setstat(void)
                    680: {
                    681:        Attrib *a;
                    682:        u_int32_t id;
                    683:        char *name;
1.36      deraadt   684:        int status = SSH2_FX_OK, ret;
1.1       markus    685:
                    686:        id = get_int();
                    687:        name = get_string(NULL);
                    688:        a = get_attrib();
1.58    ! djm       689:        debug("request %u: setstat name \"%s\"", id, name);
1.33      markus    690:        if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.58    ! djm       691:                logit("set \"%s\" size %llu", name, a->size);
1.33      markus    692:                ret = truncate(name, a->size);
                    693:                if (ret == -1)
                    694:                        status = errno_to_portable(errno);
                    695:        }
1.10      markus    696:        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58    ! djm       697:                logit("set \"%s\" mode %04o", name, a->perm);
1.1       markus    698:                ret = chmod(name, a->perm & 0777);
                    699:                if (ret == -1)
                    700:                        status = errno_to_portable(errno);
                    701:        }
1.10      markus    702:        if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58    ! djm       703:                char buf[64];
        !           704:                time_t t = a->mtime;
        !           705:
        !           706:                strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
        !           707:                    localtime(&t));
        !           708:                logit("set \"%s\" modtime %s", name, buf);
1.1       markus    709:                ret = utimes(name, attrib_to_tv(a));
                    710:                if (ret == -1)
                    711:                        status = errno_to_portable(errno);
                    712:        }
1.18      stevesk   713:        if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58    ! djm       714:                logit("set \"%s\" owner %lu group %lu", name,
        !           715:                    (u_long)a->uid, (u_long)a->gid);
1.18      stevesk   716:                ret = chown(name, a->uid, a->gid);
                    717:                if (ret == -1)
                    718:                        status = errno_to_portable(errno);
                    719:        }
1.1       markus    720:        send_status(id, status);
                    721:        xfree(name);
                    722: }
                    723:
1.28      itojun    724: static void
1.1       markus    725: process_fsetstat(void)
                    726: {
                    727:        Attrib *a;
                    728:        u_int32_t id;
                    729:        int handle, fd, ret;
1.10      markus    730:        int status = SSH2_FX_OK;
1.1       markus    731:
                    732:        id = get_int();
                    733:        handle = get_handle();
                    734:        a = get_attrib();
1.58    ! djm       735:        debug("request %u: fsetstat handle %d", id, handle);
1.1       markus    736:        fd = handle_to_fd(handle);
                    737:        if (fd < 0) {
1.10      markus    738:                status = SSH2_FX_FAILURE;
1.1       markus    739:        } else {
1.58    ! djm       740:                char *name = handle_to_name(handle);
        !           741:
1.33      markus    742:                if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
1.58    ! djm       743:                        logit("set \"%s\" size %llu", name, a->size);
1.33      markus    744:                        ret = ftruncate(fd, a->size);
                    745:                        if (ret == -1)
                    746:                                status = errno_to_portable(errno);
                    747:                }
1.10      markus    748:                if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.58    ! djm       749:                        logit("set \"%s\" mode %04o", name, a->perm);
1.1       markus    750:                        ret = fchmod(fd, a->perm & 0777);
                    751:                        if (ret == -1)
                    752:                                status = errno_to_portable(errno);
                    753:                }
1.10      markus    754:                if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.58    ! djm       755:                        char buf[64];
        !           756:                        time_t t = a->mtime;
        !           757:
        !           758:                        strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
        !           759:                            localtime(&t));
        !           760:                        logit("set \"%s\" modtime %s", name, buf);
1.1       markus    761:                        ret = futimes(fd, attrib_to_tv(a));
1.18      stevesk   762:                        if (ret == -1)
                    763:                                status = errno_to_portable(errno);
                    764:                }
                    765:                if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
1.58    ! djm       766:                        logit("set \"%s\" owner %lu group %lu", name,
        !           767:                            (u_long)a->uid, (u_long)a->gid);
1.18      stevesk   768:                        ret = fchown(fd, a->uid, a->gid);
1.1       markus    769:                        if (ret == -1)
                    770:                                status = errno_to_portable(errno);
                    771:                }
                    772:        }
                    773:        send_status(id, status);
                    774: }
                    775:
1.28      itojun    776: static void
1.1       markus    777: process_opendir(void)
                    778: {
                    779:        DIR *dirp = NULL;
                    780:        char *path;
1.10      markus    781:        int handle, status = SSH2_FX_FAILURE;
1.1       markus    782:        u_int32_t id;
                    783:
                    784:        id = get_int();
                    785:        path = get_string(NULL);
1.58    ! djm       786:        debug3("request %u: opendir", id);
        !           787:        logit("opendir \"%s\"", path);
1.17      stevesk   788:        dirp = opendir(path);
1.1       markus    789:        if (dirp == NULL) {
                    790:                status = errno_to_portable(errno);
                    791:        } else {
1.40      markus    792:                handle = handle_new(HANDLE_DIR, path, 0, dirp);
1.1       markus    793:                if (handle < 0) {
                    794:                        closedir(dirp);
                    795:                } else {
                    796:                        send_handle(id, handle);
1.10      markus    797:                        status = SSH2_FX_OK;
1.1       markus    798:                }
1.17      stevesk   799:
1.1       markus    800:        }
1.10      markus    801:        if (status != SSH2_FX_OK)
1.1       markus    802:                send_status(id, status);
                    803:        xfree(path);
                    804: }
                    805:
1.28      itojun    806: static void
1.1       markus    807: process_readdir(void)
                    808: {
                    809:        DIR *dirp;
                    810:        struct dirent *dp;
                    811:        char *path;
                    812:        int handle;
                    813:        u_int32_t id;
                    814:
                    815:        id = get_int();
                    816:        handle = get_handle();
1.58    ! djm       817:        debug("request %u: readdir \"%s\" (handle %d)", id,
        !           818:            handle_to_name(handle), handle);
1.1       markus    819:        dirp = handle_to_dir(handle);
                    820:        path = handle_to_name(handle);
                    821:        if (dirp == NULL || path == NULL) {
1.10      markus    822:                send_status(id, SSH2_FX_FAILURE);
1.1       markus    823:        } else {
                    824:                struct stat st;
1.58    ! djm       825:                char pathname[MAXPATHLEN];
1.1       markus    826:                Stat *stats;
                    827:                int nstats = 10, count = 0, i;
1.36      deraadt   828:
1.54      djm       829:                stats = xcalloc(nstats, sizeof(Stat));
1.1       markus    830:                while ((dp = readdir(dirp)) != NULL) {
                    831:                        if (count >= nstats) {
                    832:                                nstats *= 2;
1.55      djm       833:                                stats = xrealloc(stats, nstats, sizeof(Stat));
1.1       markus    834:                        }
                    835: /* XXX OVERFLOW ? */
1.30      jakob     836:                        snprintf(pathname, sizeof pathname, "%s%s%s", path,
                    837:                            strcmp(path, "/") ? "/" : "", dp->d_name);
1.1       markus    838:                        if (lstat(pathname, &st) < 0)
                    839:                                continue;
1.13      markus    840:                        stat_to_attrib(&st, &(stats[count].attrib));
1.1       markus    841:                        stats[count].name = xstrdup(dp->d_name);
1.38      djm       842:                        stats[count].long_name = ls_file(dp->d_name, &st, 0);
1.1       markus    843:                        count++;
                    844:                        /* send up to 100 entries in one message */
1.11      markus    845:                        /* XXX check packet size instead */
1.1       markus    846:                        if (count == 100)
                    847:                                break;
                    848:                }
1.10      markus    849:                if (count > 0) {
                    850:                        send_names(id, count, stats);
1.31      deraadt   851:                        for (i = 0; i < count; i++) {
1.10      markus    852:                                xfree(stats[i].name);
                    853:                                xfree(stats[i].long_name);
                    854:                        }
                    855:                } else {
                    856:                        send_status(id, SSH2_FX_EOF);
1.1       markus    857:                }
                    858:                xfree(stats);
                    859:        }
                    860: }
                    861:
1.28      itojun    862: static void
1.1       markus    863: process_remove(void)
                    864: {
                    865:        char *name;
                    866:        u_int32_t id;
1.10      markus    867:        int status = SSH2_FX_FAILURE;
1.1       markus    868:        int ret;
                    869:
                    870:        id = get_int();
                    871:        name = get_string(NULL);
1.58    ! djm       872:        debug3("request %u: remove", id);
        !           873:        logit("remove name \"%s\"", name);
1.8       markus    874:        ret = unlink(name);
1.10      markus    875:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    876:        send_status(id, status);
                    877:        xfree(name);
                    878: }
                    879:
1.28      itojun    880: static void
1.1       markus    881: process_mkdir(void)
                    882: {
                    883:        Attrib *a;
                    884:        u_int32_t id;
                    885:        char *name;
1.10      markus    886:        int ret, mode, status = SSH2_FX_FAILURE;
1.1       markus    887:
                    888:        id = get_int();
                    889:        name = get_string(NULL);
                    890:        a = get_attrib();
1.10      markus    891:        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
                    892:            a->perm & 0777 : 0777;
1.58    ! djm       893:        debug3("request %u: mkdir", id);
        !           894:        logit("mkdir name \"%s\" mode 0%o", name, mode);
1.1       markus    895:        ret = mkdir(name, mode);
1.10      markus    896:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    897:        send_status(id, status);
                    898:        xfree(name);
                    899: }
                    900:
1.28      itojun    901: static void
1.1       markus    902: process_rmdir(void)
                    903: {
                    904:        u_int32_t id;
                    905:        char *name;
                    906:        int ret, status;
                    907:
                    908:        id = get_int();
                    909:        name = get_string(NULL);
1.58    ! djm       910:        debug3("request %u: rmdir", id);
        !           911:        logit("rmdir name \"%s\"", name);
1.1       markus    912:        ret = rmdir(name);
1.10      markus    913:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    914:        send_status(id, status);
                    915:        xfree(name);
                    916: }
                    917:
1.28      itojun    918: static void
1.1       markus    919: process_realpath(void)
                    920: {
                    921:        char resolvedname[MAXPATHLEN];
                    922:        u_int32_t id;
                    923:        char *path;
                    924:
                    925:        id = get_int();
                    926:        path = get_string(NULL);
1.7       markus    927:        if (path[0] == '\0') {
                    928:                xfree(path);
                    929:                path = xstrdup(".");
                    930:        }
1.58    ! djm       931:        debug3("request %u: realpath", id);
        !           932:        verbose("realpath \"%s\"", path);
1.1       markus    933:        if (realpath(path, resolvedname) == NULL) {
                    934:                send_status(id, errno_to_portable(errno));
                    935:        } else {
                    936:                Stat s;
                    937:                attrib_clear(&s.attrib);
                    938:                s.name = s.long_name = resolvedname;
                    939:                send_names(id, 1, &s);
                    940:        }
                    941:        xfree(path);
                    942: }
                    943:
1.28      itojun    944: static void
1.1       markus    945: process_rename(void)
                    946: {
                    947:        u_int32_t id;
                    948:        char *oldpath, *newpath;
1.39      markus    949:        int status;
1.41      deraadt   950:        struct stat sb;
1.1       markus    951:
                    952:        id = get_int();
                    953:        oldpath = get_string(NULL);
                    954:        newpath = get_string(NULL);
1.58    ! djm       955:        debug3("request %u: rename", id);
        !           956:        logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
1.41      deraadt   957:        status = SSH2_FX_FAILURE;
                    958:        if (lstat(oldpath, &sb) == -1)
1.39      markus    959:                status = errno_to_portable(errno);
1.41      deraadt   960:        else if (S_ISREG(sb.st_mode)) {
                    961:                /* Race-free rename of regular files */
1.47      dtucker   962:                if (link(oldpath, newpath) == -1) {
                    963:                        if (errno == EOPNOTSUPP) {
                    964:                                struct stat st;
                    965:
                    966:                                /*
                    967:                                 * fs doesn't support links, so fall back to
                    968:                                 * stat+rename.  This is racy.
                    969:                                 */
                    970:                                if (stat(newpath, &st) == -1) {
                    971:                                        if (rename(oldpath, newpath) == -1)
                    972:                                                status =
                    973:                                                    errno_to_portable(errno);
                    974:                                        else
                    975:                                                status = SSH2_FX_OK;
                    976:                                }
                    977:                        } else {
                    978:                                status = errno_to_portable(errno);
                    979:                        }
                    980:                } else if (unlink(oldpath) == -1) {
1.41      deraadt   981:                        status = errno_to_portable(errno);
                    982:                        /* clean spare link */
                    983:                        unlink(newpath);
                    984:                } else
                    985:                        status = SSH2_FX_OK;
                    986:        } else if (stat(newpath, &sb) == -1) {
                    987:                if (rename(oldpath, newpath) == -1)
                    988:                        status = errno_to_portable(errno);
                    989:                else
                    990:                        status = SSH2_FX_OK;
                    991:        }
1.1       markus    992:        send_status(id, status);
                    993:        xfree(oldpath);
                    994:        xfree(newpath);
                    995: }
                    996:
1.28      itojun    997: static void
1.23      djm       998: process_readlink(void)
                    999: {
                   1000:        u_int32_t id;
1.26      markus   1001:        int len;
1.46      avsm     1002:        char buf[MAXPATHLEN];
1.23      djm      1003:        char *path;
                   1004:
                   1005:        id = get_int();
                   1006:        path = get_string(NULL);
1.58    ! djm      1007:        debug3("request %u: readlink", id);
        !          1008:        verbose("readlink \"%s\"", path);
1.46      avsm     1009:        if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1.23      djm      1010:                send_status(id, errno_to_portable(errno));
                   1011:        else {
                   1012:                Stat s;
1.31      deraadt  1013:
1.46      avsm     1014:                buf[len] = '\0';
1.23      djm      1015:                attrib_clear(&s.attrib);
1.46      avsm     1016:                s.name = s.long_name = buf;
1.23      djm      1017:                send_names(id, 1, &s);
                   1018:        }
                   1019:        xfree(path);
                   1020: }
                   1021:
1.28      itojun   1022: static void
1.23      djm      1023: process_symlink(void)
                   1024: {
                   1025:        u_int32_t id;
                   1026:        char *oldpath, *newpath;
1.39      markus   1027:        int ret, status;
1.23      djm      1028:
                   1029:        id = get_int();
                   1030:        oldpath = get_string(NULL);
                   1031:        newpath = get_string(NULL);
1.58    ! djm      1032:        debug3("request %u: symlink", id);
        !          1033:        logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1.39      markus   1034:        /* this will fail if 'newpath' exists */
                   1035:        ret = symlink(oldpath, newpath);
                   1036:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.23      djm      1037:        send_status(id, status);
                   1038:        xfree(oldpath);
                   1039:        xfree(newpath);
                   1040: }
                   1041:
1.28      itojun   1042: static void
1.10      markus   1043: process_extended(void)
                   1044: {
                   1045:        u_int32_t id;
                   1046:        char *request;
                   1047:
                   1048:        id = get_int();
                   1049:        request = get_string(NULL);
                   1050:        send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */
                   1051:        xfree(request);
                   1052: }
1.1       markus   1053:
                   1054: /* stolen from ssh-agent */
                   1055:
1.28      itojun   1056: static void
1.1       markus   1057: process(void)
                   1058: {
1.9       markus   1059:        u_int msg_len;
1.34      markus   1060:        u_int buf_len;
                   1061:        u_int consumed;
1.9       markus   1062:        u_int type;
                   1063:        u_char *cp;
1.1       markus   1064:
1.34      markus   1065:        buf_len = buffer_len(&iqueue);
                   1066:        if (buf_len < 5)
1.1       markus   1067:                return;         /* Incomplete message. */
1.32      stevesk  1068:        cp = buffer_ptr(&iqueue);
1.57      djm      1069:        msg_len = get_u32(cp);
1.50      djm      1070:        if (msg_len > SFTP_MAX_MSG_LENGTH) {
1.58    ! djm      1071:                error("bad message from %s local user %s",
        !          1072:                    client_addr, pw->pw_name);
        !          1073:                cleanup_exit(11);
1.1       markus   1074:        }
1.34      markus   1075:        if (buf_len < msg_len + 4)
1.1       markus   1076:                return;
                   1077:        buffer_consume(&iqueue, 4);
1.34      markus   1078:        buf_len -= 4;
1.1       markus   1079:        type = buffer_get_char(&iqueue);
                   1080:        switch (type) {
1.10      markus   1081:        case SSH2_FXP_INIT:
1.1       markus   1082:                process_init();
                   1083:                break;
1.10      markus   1084:        case SSH2_FXP_OPEN:
1.1       markus   1085:                process_open();
                   1086:                break;
1.10      markus   1087:        case SSH2_FXP_CLOSE:
1.1       markus   1088:                process_close();
                   1089:                break;
1.10      markus   1090:        case SSH2_FXP_READ:
1.1       markus   1091:                process_read();
                   1092:                break;
1.10      markus   1093:        case SSH2_FXP_WRITE:
1.1       markus   1094:                process_write();
                   1095:                break;
1.10      markus   1096:        case SSH2_FXP_LSTAT:
1.1       markus   1097:                process_lstat();
                   1098:                break;
1.10      markus   1099:        case SSH2_FXP_FSTAT:
1.1       markus   1100:                process_fstat();
                   1101:                break;
1.10      markus   1102:        case SSH2_FXP_SETSTAT:
1.1       markus   1103:                process_setstat();
                   1104:                break;
1.10      markus   1105:        case SSH2_FXP_FSETSTAT:
1.1       markus   1106:                process_fsetstat();
                   1107:                break;
1.10      markus   1108:        case SSH2_FXP_OPENDIR:
1.1       markus   1109:                process_opendir();
                   1110:                break;
1.10      markus   1111:        case SSH2_FXP_READDIR:
1.1       markus   1112:                process_readdir();
                   1113:                break;
1.10      markus   1114:        case SSH2_FXP_REMOVE:
1.1       markus   1115:                process_remove();
                   1116:                break;
1.10      markus   1117:        case SSH2_FXP_MKDIR:
1.1       markus   1118:                process_mkdir();
                   1119:                break;
1.10      markus   1120:        case SSH2_FXP_RMDIR:
1.1       markus   1121:                process_rmdir();
                   1122:                break;
1.10      markus   1123:        case SSH2_FXP_REALPATH:
1.1       markus   1124:                process_realpath();
                   1125:                break;
1.10      markus   1126:        case SSH2_FXP_STAT:
1.1       markus   1127:                process_stat();
                   1128:                break;
1.10      markus   1129:        case SSH2_FXP_RENAME:
1.1       markus   1130:                process_rename();
1.23      djm      1131:                break;
                   1132:        case SSH2_FXP_READLINK:
                   1133:                process_readlink();
                   1134:                break;
                   1135:        case SSH2_FXP_SYMLINK:
                   1136:                process_symlink();
1.1       markus   1137:                break;
1.10      markus   1138:        case SSH2_FXP_EXTENDED:
                   1139:                process_extended();
                   1140:                break;
1.1       markus   1141:        default:
                   1142:                error("Unknown message %d", type);
                   1143:                break;
                   1144:        }
1.34      markus   1145:        /* discard the remaining bytes from the current packet */
                   1146:        if (buf_len < buffer_len(&iqueue))
1.58    ! djm      1147:                fatal("iqueue grew unexpectedly");
1.34      markus   1148:        consumed = buf_len - buffer_len(&iqueue);
                   1149:        if (msg_len < consumed)
                   1150:                fatal("msg_len %d < consumed %d", msg_len, consumed);
                   1151:        if (msg_len > consumed)
                   1152:                buffer_consume(&iqueue, msg_len - consumed);
1.1       markus   1153: }
                   1154:
1.58    ! djm      1155: /* Cleanup handler that logs active handles upon normal exit */
        !          1156: void
        !          1157: cleanup_exit(int i)
        !          1158: {
        !          1159:        if (pw != NULL && client_addr != NULL) {
        !          1160:                handle_log_exit();
        !          1161:                logit("session closed for local user %s from [%s]",
        !          1162:                    pw->pw_name, client_addr);
        !          1163:        }
        !          1164:        _exit(i);
        !          1165: }
        !          1166:
        !          1167: static void
        !          1168: usage(void)
        !          1169: {
        !          1170:        extern char *__progname;
        !          1171:
        !          1172:        fprintf(stderr,
        !          1173:            "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
        !          1174:        exit(1);
        !          1175: }
        !          1176:
1.1       markus   1177: int
1.58    ! djm      1178: main(int argc, char **argv)
1.1       markus   1179: {
1.21      millert  1180:        fd_set *rset, *wset;
1.58    ! djm      1181:        int in, out, max, ch, skipargs = 0, log_stderr = 0;
1.21      millert  1182:        ssize_t len, olen, set_size;
1.58    ! djm      1183:        SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
        !          1184:        char *cp;
        !          1185:
        !          1186:        extern int optind;
        !          1187:        extern char *optarg;
        !          1188:        extern char *__progname;
1.49      djm      1189:
                   1190:        /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
                   1191:        sanitise_stdfd();
1.24      deraadt  1192:
1.58    ! djm      1193:        log_init(__progname, log_level, log_facility, log_stderr);
        !          1194:
        !          1195:        while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
        !          1196:                switch (ch) {
        !          1197:                case 'c':
        !          1198:                        /*
        !          1199:                         * Ignore all arguments if we are invoked as a
        !          1200:                         * shell using "sftp-server -c command"
        !          1201:                         */
        !          1202:                        skipargs = 1;
        !          1203:                        break;
        !          1204:                case 'e':
        !          1205:                        log_stderr = 1;
        !          1206:                        break;
        !          1207:                case 'l':
        !          1208:                        log_level = log_level_number(optarg);
        !          1209:                        if (log_level == SYSLOG_LEVEL_NOT_SET)
        !          1210:                                error("Invalid log level \"%s\"", optarg);
        !          1211:                        break;
        !          1212:                case 'f':
        !          1213:                        log_facility = log_facility_number(optarg);
        !          1214:                        if (log_level == SYSLOG_FACILITY_NOT_SET)
        !          1215:                                error("Invalid log facility \"%s\"", optarg);
        !          1216:                        break;
        !          1217:                case 'h':
        !          1218:                default:
        !          1219:                        usage();
        !          1220:                }
        !          1221:        }
        !          1222:
        !          1223:        log_init(__progname, log_level, log_facility, log_stderr);
        !          1224:
        !          1225:        if ((cp = getenv("SSH_CONNECTION")) != NULL) {
        !          1226:                client_addr = xstrdup(cp);
        !          1227:                if ((cp = strchr(client_addr, ' ')) == NULL)
        !          1228:                        fatal("Malformed SSH_CONNECTION variable: \"%s\"",
        !          1229:                            getenv("SSH_CONNECTION"));
        !          1230:                *cp = '\0';
        !          1231:        } else
        !          1232:                client_addr = xstrdup("UNKNOWN");
        !          1233:
        !          1234:        if ((pw = getpwuid(getuid())) == NULL)
        !          1235:                fatal("No user found for uid %lu", (u_long)getuid());
        !          1236:        pw = pwcopy(pw);
        !          1237:
        !          1238:        logit("session opened for local user %s from [%s]",
        !          1239:            pw->pw_name, client_addr);
1.1       markus   1240:
                   1241:        handle_init();
1.10      markus   1242:
1.1       markus   1243:        in = dup(STDIN_FILENO);
                   1244:        out = dup(STDOUT_FILENO);
                   1245:
                   1246:        max = 0;
                   1247:        if (in > max)
                   1248:                max = in;
                   1249:        if (out > max)
                   1250:                max = out;
                   1251:
                   1252:        buffer_init(&iqueue);
                   1253:        buffer_init(&oqueue);
                   1254:
1.21      millert  1255:        set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
                   1256:        rset = (fd_set *)xmalloc(set_size);
                   1257:        wset = (fd_set *)xmalloc(set_size);
                   1258:
1.1       markus   1259:        for (;;) {
1.21      millert  1260:                memset(rset, 0, set_size);
                   1261:                memset(wset, 0, set_size);
1.1       markus   1262:
1.21      millert  1263:                FD_SET(in, rset);
1.1       markus   1264:                olen = buffer_len(&oqueue);
                   1265:                if (olen > 0)
1.21      millert  1266:                        FD_SET(out, wset);
1.1       markus   1267:
1.21      millert  1268:                if (select(max+1, rset, wset, NULL, NULL) < 0) {
1.1       markus   1269:                        if (errno == EINTR)
                   1270:                                continue;
1.58    ! djm      1271:                        error("select: %s", strerror(errno));
        !          1272:                        cleanup_exit(2);
1.1       markus   1273:                }
                   1274:
                   1275:                /* copy stdin to iqueue */
1.21      millert  1276:                if (FD_ISSET(in, rset)) {
1.1       markus   1277:                        char buf[4*4096];
                   1278:                        len = read(in, buf, sizeof buf);
                   1279:                        if (len == 0) {
                   1280:                                debug("read eof");
1.58    ! djm      1281:                                cleanup_exit(0);
1.1       markus   1282:                        } else if (len < 0) {
1.58    ! djm      1283:                                error("read: %s", strerror(errno));
        !          1284:                                cleanup_exit(1);
1.1       markus   1285:                        } else {
                   1286:                                buffer_append(&iqueue, buf, len);
                   1287:                        }
                   1288:                }
                   1289:                /* send oqueue to stdout */
1.21      millert  1290:                if (FD_ISSET(out, wset)) {
1.1       markus   1291:                        len = write(out, buffer_ptr(&oqueue), olen);
                   1292:                        if (len < 0) {
1.58    ! djm      1293:                                error("write: %s", strerror(errno));
        !          1294:                                cleanup_exit(1);
1.1       markus   1295:                        } else {
                   1296:                                buffer_consume(&oqueue, len);
                   1297:                        }
                   1298:                }
                   1299:                /* process requests from client */
                   1300:                process();
                   1301:        }
                   1302: }