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

1.1       markus      1: /*
                      2:  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
                      3:  *
                      4:  * Redistribution and use in source and binary forms, with or without
                      5:  * modification, are permitted provided that the following conditions
                      6:  * are met:
                      7:  * 1. Redistributions of source code must retain the above copyright
                      8:  *    notice, this list of conditions and the following disclaimer.
                      9:  * 2. Redistributions in binary form must reproduce the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer in the
                     11:  *    documentation and/or other materials provided with the distribution.
                     12:  *
                     13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     14:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     15:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     16:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     17:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     18:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     19:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     20:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     21:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     22:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     23:  */
                     24: #include "includes.h"
1.16    ! deraadt    25: RCSID("$OpenBSD: sftp-server.c,v 1.15 2001/02/04 11:11:54 djm Exp $");
1.1       markus     26:
                     27: #include "buffer.h"
                     28: #include "bufaux.h"
                     29: #include "getput.h"
1.14      markus     30: #include "log.h"
1.1       markus     31: #include "xmalloc.h"
                     32:
1.10      markus     33: #include "sftp.h"
1.15      djm        34: #include "sftp-common.h"
1.1       markus     35:
                     36: /* helper */
1.10      markus     37: #define get_int64()                    buffer_get_int64(&iqueue);
1.1       markus     38: #define get_int()                      buffer_get_int(&iqueue);
                     39: #define get_string(lenp)               buffer_get_string(&iqueue, lenp);
1.10      markus     40: #define TRACE                          debug
1.1       markus     41:
                     42: /* input and output queue */
                     43: Buffer iqueue;
                     44: Buffer oqueue;
                     45:
                     46: /* portable attibutes, etc. */
                     47:
                     48: typedef struct Stat Stat;
                     49:
1.15      djm        50: struct Stat {
1.1       markus     51:        char *name;
                     52:        char *long_name;
                     53:        Attrib attrib;
                     54: };
                     55:
                     56: int
1.2       markus     57: errno_to_portable(int unixerrno)
1.1       markus     58: {
                     59:        int ret = 0;
1.2       markus     60:        switch (unixerrno) {
1.1       markus     61:        case 0:
1.10      markus     62:                ret = SSH2_FX_OK;
1.1       markus     63:                break;
                     64:        case ENOENT:
                     65:        case ENOTDIR:
                     66:        case EBADF:
                     67:        case ELOOP:
1.10      markus     68:                ret = SSH2_FX_NO_SUCH_FILE;
1.1       markus     69:                break;
                     70:        case EPERM:
                     71:        case EACCES:
                     72:        case EFAULT:
1.10      markus     73:                ret = SSH2_FX_PERMISSION_DENIED;
1.1       markus     74:                break;
                     75:        case ENAMETOOLONG:
                     76:        case EINVAL:
1.10      markus     77:                ret = SSH2_FX_BAD_MESSAGE;
1.1       markus     78:                break;
                     79:        default:
1.10      markus     80:                ret = SSH2_FX_FAILURE;
1.1       markus     81:                break;
                     82:        }
                     83:        return ret;
                     84: }
                     85:
                     86: int
                     87: flags_from_portable(int pflags)
                     88: {
                     89:        int flags = 0;
1.10      markus     90:        if (pflags & SSH2_FXF_READ &&
                     91:            pflags & SSH2_FXF_WRITE) {
1.1       markus     92:                flags = O_RDWR;
1.10      markus     93:        } else if (pflags & SSH2_FXF_READ) {
1.1       markus     94:                flags = O_RDONLY;
1.10      markus     95:        } else if (pflags & SSH2_FXF_WRITE) {
1.1       markus     96:                flags = O_WRONLY;
                     97:        }
1.10      markus     98:        if (pflags & SSH2_FXF_CREAT)
1.1       markus     99:                flags |= O_CREAT;
1.10      markus    100:        if (pflags & SSH2_FXF_TRUNC)
1.1       markus    101:                flags |= O_TRUNC;
1.10      markus    102:        if (pflags & SSH2_FXF_EXCL)
1.1       markus    103:                flags |= O_EXCL;
                    104:        return flags;
                    105: }
                    106:
                    107: Attrib *
                    108: get_attrib(void)
                    109: {
                    110:        return decode_attrib(&iqueue);
                    111: }
                    112:
                    113: /* handle handles */
                    114:
                    115: typedef struct Handle Handle;
                    116: struct Handle {
                    117:        int use;
                    118:        DIR *dirp;
                    119:        int fd;
                    120:        char *name;
                    121: };
                    122: enum {
                    123:        HANDLE_UNUSED,
                    124:        HANDLE_DIR,
                    125:        HANDLE_FILE
                    126: };
                    127: Handle handles[100];
                    128:
                    129: void
                    130: handle_init(void)
                    131: {
                    132:        int i;
                    133:        for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
                    134:                handles[i].use = HANDLE_UNUSED;
                    135: }
                    136:
                    137: int
                    138: handle_new(int use, char *name, int fd, DIR *dirp)
                    139: {
                    140:        int i;
                    141:        for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
                    142:                if (handles[i].use == HANDLE_UNUSED) {
                    143:                        handles[i].use = use;
                    144:                        handles[i].dirp = dirp;
                    145:                        handles[i].fd = fd;
                    146:                        handles[i].name = name;
                    147:                        return i;
                    148:                }
                    149:        }
                    150:        return -1;
                    151: }
                    152:
                    153: int
                    154: handle_is_ok(int i, int type)
                    155: {
1.10      markus    156:        return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
                    157:            handles[i].use == type;
1.1       markus    158: }
                    159:
                    160: int
                    161: handle_to_string(int handle, char **stringp, int *hlenp)
                    162: {
                    163:        if (stringp == NULL || hlenp == NULL)
                    164:                return -1;
1.13      markus    165:        *stringp = xmalloc(sizeof(int32_t));
                    166:        PUT_32BIT(*stringp, handle);
                    167:        *hlenp = sizeof(int32_t);
1.1       markus    168:        return 0;
                    169: }
                    170:
                    171: int
1.5       markus    172: handle_from_string(char *handle, u_int hlen)
1.1       markus    173: {
1.13      markus    174:        int val;
                    175:        if (hlen != sizeof(int32_t))
1.1       markus    176:                return -1;
1.13      markus    177:        val = GET_32BIT(handle);
1.1       markus    178:        if (handle_is_ok(val, HANDLE_FILE) ||
                    179:            handle_is_ok(val, HANDLE_DIR))
                    180:                return val;
                    181:        return -1;
                    182: }
                    183:
                    184: char *
                    185: handle_to_name(int handle)
                    186: {
                    187:        if (handle_is_ok(handle, HANDLE_DIR)||
                    188:            handle_is_ok(handle, HANDLE_FILE))
                    189:                return handles[handle].name;
                    190:        return NULL;
                    191: }
                    192:
                    193: DIR *
                    194: handle_to_dir(int handle)
                    195: {
                    196:        if (handle_is_ok(handle, HANDLE_DIR))
                    197:                return handles[handle].dirp;
                    198:        return NULL;
                    199: }
                    200:
                    201: int
                    202: handle_to_fd(int handle)
                    203: {
                    204:        if (handle_is_ok(handle, HANDLE_FILE))
                    205:                return handles[handle].fd;
                    206:        return -1;
                    207: }
                    208:
                    209: int
                    210: handle_close(int handle)
                    211: {
                    212:        int ret = -1;
                    213:        if (handle_is_ok(handle, HANDLE_FILE)) {
                    214:                ret = close(handles[handle].fd);
                    215:                handles[handle].use = HANDLE_UNUSED;
                    216:        } else if (handle_is_ok(handle, HANDLE_DIR)) {
                    217:                ret = closedir(handles[handle].dirp);
                    218:                handles[handle].use = HANDLE_UNUSED;
                    219:        } else {
                    220:                errno = ENOENT;
                    221:        }
                    222:        return ret;
                    223: }
                    224:
                    225: int
                    226: get_handle(void)
                    227: {
                    228:        char *handle;
1.10      markus    229:        int val = -1;
1.5       markus    230:        u_int hlen;
1.1       markus    231:        handle = get_string(&hlen);
1.10      markus    232:        if (hlen < 256)
                    233:                val = handle_from_string(handle, hlen);
1.1       markus    234:        xfree(handle);
                    235:        return val;
                    236: }
                    237:
                    238: /* send replies */
                    239:
                    240: void
                    241: send_msg(Buffer *m)
                    242: {
                    243:        int mlen = buffer_len(m);
                    244:        buffer_put_int(&oqueue, mlen);
                    245:        buffer_append(&oqueue, buffer_ptr(m), mlen);
                    246:        buffer_consume(m, mlen);
                    247: }
                    248:
                    249: void
                    250: send_status(u_int32_t id, u_int32_t error)
                    251: {
                    252:        Buffer msg;
                    253:        TRACE("sent status id %d error %d", id, error);
                    254:        buffer_init(&msg);
1.10      markus    255:        buffer_put_char(&msg, SSH2_FXP_STATUS);
1.1       markus    256:        buffer_put_int(&msg, id);
                    257:        buffer_put_int(&msg, error);
                    258:        send_msg(&msg);
                    259:        buffer_free(&msg);
                    260: }
                    261: void
                    262: send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
                    263: {
                    264:        Buffer msg;
                    265:        buffer_init(&msg);
                    266:        buffer_put_char(&msg, type);
                    267:        buffer_put_int(&msg, id);
                    268:        buffer_put_string(&msg, data, dlen);
                    269:        send_msg(&msg);
                    270:        buffer_free(&msg);
                    271: }
                    272:
                    273: void
                    274: send_data(u_int32_t id, char *data, int dlen)
                    275: {
                    276:        TRACE("sent data id %d len %d", id, dlen);
1.10      markus    277:        send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
1.1       markus    278: }
                    279:
                    280: void
                    281: send_handle(u_int32_t id, int handle)
                    282: {
                    283:        char *string;
                    284:        int hlen;
                    285:        handle_to_string(handle, &string, &hlen);
                    286:        TRACE("sent handle id %d handle %d", id, handle);
1.10      markus    287:        send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
1.1       markus    288:        xfree(string);
                    289: }
                    290:
                    291: void
                    292: send_names(u_int32_t id, int count, Stat *stats)
                    293: {
                    294:        Buffer msg;
                    295:        int i;
                    296:        buffer_init(&msg);
1.10      markus    297:        buffer_put_char(&msg, SSH2_FXP_NAME);
1.1       markus    298:        buffer_put_int(&msg, id);
                    299:        buffer_put_int(&msg, count);
                    300:        TRACE("sent names id %d count %d", id, count);
                    301:        for (i = 0; i < count; i++) {
                    302:                buffer_put_cstring(&msg, stats[i].name);
                    303:                buffer_put_cstring(&msg, stats[i].long_name);
                    304:                encode_attrib(&msg, &stats[i].attrib);
                    305:        }
                    306:        send_msg(&msg);
                    307:        buffer_free(&msg);
                    308: }
                    309:
                    310: void
                    311: send_attrib(u_int32_t id, Attrib *a)
                    312: {
                    313:        Buffer msg;
                    314:        TRACE("sent attrib id %d have 0x%x", id, a->flags);
                    315:        buffer_init(&msg);
1.10      markus    316:        buffer_put_char(&msg, SSH2_FXP_ATTRS);
1.1       markus    317:        buffer_put_int(&msg, id);
                    318:        encode_attrib(&msg, a);
                    319:        send_msg(&msg);
                    320:        buffer_free(&msg);
                    321: }
                    322:
                    323: /* parse incoming */
                    324:
                    325: void
                    326: process_init(void)
                    327: {
                    328:        Buffer msg;
                    329:        int version = buffer_get_int(&iqueue);
                    330:
                    331:        TRACE("client version %d", version);
                    332:        buffer_init(&msg);
1.10      markus    333:        buffer_put_char(&msg, SSH2_FXP_VERSION);
                    334:        buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
1.1       markus    335:        send_msg(&msg);
                    336:        buffer_free(&msg);
                    337: }
                    338:
                    339: void
                    340: process_open(void)
                    341: {
                    342:        u_int32_t id, pflags;
                    343:        Attrib *a;
                    344:        char *name;
1.10      markus    345:        int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
1.1       markus    346:
                    347:        id = get_int();
                    348:        name = get_string(NULL);
1.10      markus    349:        pflags = get_int();             /* portable flags */
1.1       markus    350:        a = get_attrib();
                    351:        flags = flags_from_portable(pflags);
1.10      markus    352:        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
1.1       markus    353:        TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
                    354:        fd = open(name, flags, mode);
                    355:        if (fd < 0) {
                    356:                status = errno_to_portable(errno);
                    357:        } else {
                    358:                handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);
                    359:                if (handle < 0) {
                    360:                        close(fd);
                    361:                } else {
                    362:                        send_handle(id, handle);
1.10      markus    363:                        status = SSH2_FX_OK;
1.1       markus    364:                }
                    365:        }
1.10      markus    366:        if (status != SSH2_FX_OK)
1.1       markus    367:                send_status(id, status);
                    368:        xfree(name);
                    369: }
                    370:
                    371: void
                    372: process_close(void)
                    373: {
                    374:        u_int32_t id;
1.10      markus    375:        int handle, ret, status = SSH2_FX_FAILURE;
1.1       markus    376:
                    377:        id = get_int();
                    378:        handle = get_handle();
                    379:        TRACE("close id %d handle %d", id, handle);
                    380:        ret = handle_close(handle);
1.10      markus    381:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    382:        send_status(id, status);
                    383: }
                    384:
                    385: void
                    386: process_read(void)
                    387: {
                    388:        char buf[64*1024];
1.10      markus    389:        u_int32_t id, len;
                    390:        int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1       markus    391:        u_int64_t off;
                    392:
                    393:        id = get_int();
                    394:        handle = get_handle();
1.10      markus    395:        off = get_int64();
1.1       markus    396:        len = get_int();
                    397:
1.16    ! deraadt   398:        TRACE("read id %d handle %d off %qd len %d", id, handle,
        !           399:            (unsigned long long)off, len);
1.1       markus    400:        if (len > sizeof buf) {
                    401:                len = sizeof buf;
                    402:                log("read change len %d", len);
                    403:        }
                    404:        fd = handle_to_fd(handle);
                    405:        if (fd >= 0) {
                    406:                if (lseek(fd, off, SEEK_SET) < 0) {
                    407:                        error("process_read: seek failed");
                    408:                        status = errno_to_portable(errno);
                    409:                } else {
                    410:                        ret = read(fd, buf, len);
                    411:                        if (ret < 0) {
                    412:                                status = errno_to_portable(errno);
                    413:                        } else if (ret == 0) {
1.10      markus    414:                                status = SSH2_FX_EOF;
1.1       markus    415:                        } else {
                    416:                                send_data(id, buf, ret);
1.10      markus    417:                                status = SSH2_FX_OK;
1.1       markus    418:                        }
                    419:                }
                    420:        }
1.10      markus    421:        if (status != SSH2_FX_OK)
1.1       markus    422:                send_status(id, status);
                    423: }
                    424:
                    425: void
                    426: process_write(void)
                    427: {
1.10      markus    428:        u_int32_t id;
1.1       markus    429:        u_int64_t off;
1.5       markus    430:        u_int len;
1.10      markus    431:        int handle, fd, ret, status = SSH2_FX_FAILURE;
1.1       markus    432:        char *data;
                    433:
                    434:        id = get_int();
                    435:        handle = get_handle();
1.10      markus    436:        off = get_int64();
1.1       markus    437:        data = get_string(&len);
                    438:
1.16    ! deraadt   439:        TRACE("write id %d handle %d off %qd len %d", id, handle,
        !           440:            (unsigned long long)off, len);
1.1       markus    441:        fd = handle_to_fd(handle);
                    442:        if (fd >= 0) {
                    443:                if (lseek(fd, off, SEEK_SET) < 0) {
                    444:                        status = errno_to_portable(errno);
                    445:                        error("process_write: seek failed");
                    446:                } else {
                    447: /* XXX ATOMICIO ? */
                    448:                        ret = write(fd, data, len);
                    449:                        if (ret == -1) {
                    450:                                error("process_write: write failed");
                    451:                                status = errno_to_portable(errno);
                    452:                        } else if (ret == len) {
1.10      markus    453:                                status = SSH2_FX_OK;
1.1       markus    454:                        } else {
                    455:                                log("nothing at all written");
                    456:                        }
                    457:                }
                    458:        }
                    459:        send_status(id, status);
                    460:        xfree(data);
                    461: }
                    462:
                    463: void
                    464: process_do_stat(int do_lstat)
                    465: {
1.13      markus    466:        Attrib a;
1.1       markus    467:        struct stat st;
                    468:        u_int32_t id;
                    469:        char *name;
1.10      markus    470:        int ret, status = SSH2_FX_FAILURE;
1.1       markus    471:
                    472:        id = get_int();
                    473:        name = get_string(NULL);
                    474:        TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
                    475:        ret = do_lstat ? lstat(name, &st) : stat(name, &st);
                    476:        if (ret < 0) {
                    477:                status = errno_to_portable(errno);
                    478:        } else {
1.13      markus    479:                stat_to_attrib(&st, &a);
                    480:                send_attrib(id, &a);
1.10      markus    481:                status = SSH2_FX_OK;
1.1       markus    482:        }
1.10      markus    483:        if (status != SSH2_FX_OK)
1.1       markus    484:                send_status(id, status);
                    485:        xfree(name);
                    486: }
                    487:
                    488: void
                    489: process_stat(void)
                    490: {
                    491:        process_do_stat(0);
                    492: }
                    493:
                    494: void
                    495: process_lstat(void)
                    496: {
                    497:        process_do_stat(1);
                    498: }
                    499:
                    500: void
                    501: process_fstat(void)
                    502: {
1.13      markus    503:        Attrib a;
1.1       markus    504:        struct stat st;
                    505:        u_int32_t id;
1.10      markus    506:        int fd, ret, handle, status = SSH2_FX_FAILURE;
1.1       markus    507:
                    508:        id = get_int();
                    509:        handle = get_handle();
                    510:        TRACE("fstat id %d handle %d", id, handle);
                    511:        fd = handle_to_fd(handle);
                    512:        if (fd  >= 0) {
                    513:                ret = fstat(fd, &st);
                    514:                if (ret < 0) {
                    515:                        status = errno_to_portable(errno);
                    516:                } else {
1.13      markus    517:                        stat_to_attrib(&st, &a);
                    518:                        send_attrib(id, &a);
1.10      markus    519:                        status = SSH2_FX_OK;
1.1       markus    520:                }
                    521:        }
1.10      markus    522:        if (status != SSH2_FX_OK)
1.1       markus    523:                send_status(id, status);
                    524: }
                    525:
                    526: struct timeval *
                    527: attrib_to_tv(Attrib *a)
                    528: {
                    529:        static struct timeval tv[2];
                    530:        tv[0].tv_sec = a->atime;
                    531:        tv[0].tv_usec = 0;
                    532:        tv[1].tv_sec = a->mtime;
                    533:        tv[1].tv_usec = 0;
                    534:        return tv;
                    535: }
                    536:
                    537: void
                    538: process_setstat(void)
                    539: {
                    540:        Attrib *a;
                    541:        u_int32_t id;
                    542:        char *name;
                    543:        int ret;
1.10      markus    544:        int status = SSH2_FX_OK;
1.1       markus    545:
                    546:        id = get_int();
                    547:        name = get_string(NULL);
                    548:        a = get_attrib();
                    549:        TRACE("setstat id %d name %s", id, name);
1.10      markus    550:        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1       markus    551:                ret = chmod(name, a->perm & 0777);
                    552:                if (ret == -1)
                    553:                        status = errno_to_portable(errno);
                    554:        }
1.10      markus    555:        if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1       markus    556:                ret = utimes(name, attrib_to_tv(a));
                    557:                if (ret == -1)
                    558:                        status = errno_to_portable(errno);
                    559:        }
                    560:        send_status(id, status);
                    561:        xfree(name);
                    562: }
                    563:
                    564: void
                    565: process_fsetstat(void)
                    566: {
                    567:        Attrib *a;
                    568:        u_int32_t id;
                    569:        int handle, fd, ret;
1.10      markus    570:        int status = SSH2_FX_OK;
1.1       markus    571:
                    572:        id = get_int();
                    573:        handle = get_handle();
                    574:        a = get_attrib();
                    575:        TRACE("fsetstat id %d handle %d", id, handle);
                    576:        fd = handle_to_fd(handle);
                    577:        if (fd < 0) {
1.10      markus    578:                status = SSH2_FX_FAILURE;
1.1       markus    579:        } else {
1.10      markus    580:                if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1.1       markus    581:                        ret = fchmod(fd, a->perm & 0777);
                    582:                        if (ret == -1)
                    583:                                status = errno_to_portable(errno);
                    584:                }
1.10      markus    585:                if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1.1       markus    586:                        ret = futimes(fd, attrib_to_tv(a));
                    587:                        if (ret == -1)
                    588:                                status = errno_to_portable(errno);
                    589:                }
                    590:        }
                    591:        send_status(id, status);
                    592: }
                    593:
                    594: void
                    595: process_opendir(void)
                    596: {
                    597:        DIR *dirp = NULL;
                    598:        char *path;
1.10      markus    599:        int handle, status = SSH2_FX_FAILURE;
1.1       markus    600:        u_int32_t id;
                    601:
                    602:        id = get_int();
                    603:        path = get_string(NULL);
                    604:        TRACE("opendir id %d path %s", id, path);
                    605:        dirp = opendir(path);
                    606:        if (dirp == NULL) {
                    607:                status = errno_to_portable(errno);
                    608:        } else {
                    609:                handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp);
                    610:                if (handle < 0) {
                    611:                        closedir(dirp);
                    612:                } else {
                    613:                        send_handle(id, handle);
1.10      markus    614:                        status = SSH2_FX_OK;
1.1       markus    615:                }
                    616:
                    617:        }
1.10      markus    618:        if (status != SSH2_FX_OK)
1.1       markus    619:                send_status(id, status);
                    620:        xfree(path);
                    621: }
                    622:
1.10      markus    623: /*
1.12      markus    624:  * drwxr-xr-x    5 markus   markus       1024 Jan 13 18:39 .ssh
1.10      markus    625:  */
1.1       markus    626: char *
                    627: ls_file(char *name, struct stat *st)
                    628: {
1.12      markus    629:        int sz = 0;
                    630:        struct passwd *pw;
                    631:        struct group *gr;
                    632:        struct tm *ltime = localtime(&st->st_mtime);
                    633:        char *user, *group;
                    634:        char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
                    635:
                    636:        strmode(st->st_mode, mode);
                    637:        if ((pw = getpwuid(st->st_uid)) != NULL) {
                    638:                user = pw->pw_name;
                    639:        } else {
                    640:                snprintf(ubuf, sizeof ubuf, "%d", st->st_uid);
                    641:                user = ubuf;
                    642:        }
                    643:        if ((gr = getgrgid(st->st_gid)) != NULL) {
                    644:                group = gr->gr_name;
                    645:        } else {
                    646:                snprintf(gbuf, sizeof gbuf, "%d", st->st_gid);
                    647:                group = gbuf;
                    648:        }
                    649:        if (ltime != NULL) {
                    650:                if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
                    651:                        sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
                    652:                else
                    653:                        sz = strftime(tbuf, sizeof tbuf, "%b %e  %Y", ltime);
                    654:        }
                    655:        if (sz == 0)
                    656:                tbuf[0] = '\0';
                    657:        snprintf(buf, sizeof buf, "%s %3d %-8.8s %-8.8s %8qd %s %s", mode,
                    658:            st->st_nlink, user, group, (long long)st->st_size, tbuf, name);
1.1       markus    659:        return xstrdup(buf);
                    660: }
                    661:
                    662: void
                    663: process_readdir(void)
                    664: {
                    665:        DIR *dirp;
                    666:        struct dirent *dp;
                    667:        char *path;
                    668:        int handle;
                    669:        u_int32_t id;
                    670:
                    671:        id = get_int();
                    672:        handle = get_handle();
                    673:        TRACE("readdir id %d handle %d", id, handle);
                    674:        dirp = handle_to_dir(handle);
                    675:        path = handle_to_name(handle);
                    676:        if (dirp == NULL || path == NULL) {
1.10      markus    677:                send_status(id, SSH2_FX_FAILURE);
1.1       markus    678:        } else {
                    679:                struct stat st;
                    680:                char pathname[1024];
                    681:                Stat *stats;
                    682:                int nstats = 10, count = 0, i;
                    683:                stats = xmalloc(nstats * sizeof(Stat));
                    684:                while ((dp = readdir(dirp)) != NULL) {
                    685:                        if (count >= nstats) {
                    686:                                nstats *= 2;
                    687:                                stats = xrealloc(stats, nstats * sizeof(Stat));
                    688:                        }
                    689: /* XXX OVERFLOW ? */
                    690:                        snprintf(pathname, sizeof pathname,
                    691:                            "%s/%s", path, dp->d_name);
                    692:                        if (lstat(pathname, &st) < 0)
                    693:                                continue;
1.13      markus    694:                        stat_to_attrib(&st, &(stats[count].attrib));
1.1       markus    695:                        stats[count].name = xstrdup(dp->d_name);
                    696:                        stats[count].long_name = ls_file(dp->d_name, &st);
                    697:                        count++;
                    698:                        /* send up to 100 entries in one message */
1.11      markus    699:                        /* XXX check packet size instead */
1.1       markus    700:                        if (count == 100)
                    701:                                break;
                    702:                }
1.10      markus    703:                if (count > 0) {
                    704:                        send_names(id, count, stats);
                    705:                        for(i = 0; i < count; i++) {
                    706:                                xfree(stats[i].name);
                    707:                                xfree(stats[i].long_name);
                    708:                        }
                    709:                } else {
                    710:                        send_status(id, SSH2_FX_EOF);
1.1       markus    711:                }
                    712:                xfree(stats);
                    713:        }
                    714: }
                    715:
                    716: void
                    717: process_remove(void)
                    718: {
                    719:        char *name;
                    720:        u_int32_t id;
1.10      markus    721:        int status = SSH2_FX_FAILURE;
1.1       markus    722:        int ret;
                    723:
                    724:        id = get_int();
                    725:        name = get_string(NULL);
                    726:        TRACE("remove id %d name %s", id, name);
1.8       markus    727:        ret = unlink(name);
1.10      markus    728:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    729:        send_status(id, status);
                    730:        xfree(name);
                    731: }
                    732:
                    733: void
                    734: process_mkdir(void)
                    735: {
                    736:        Attrib *a;
                    737:        u_int32_t id;
                    738:        char *name;
1.10      markus    739:        int ret, mode, status = SSH2_FX_FAILURE;
1.1       markus    740:
                    741:        id = get_int();
                    742:        name = get_string(NULL);
                    743:        a = get_attrib();
1.10      markus    744:        mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
                    745:            a->perm & 0777 : 0777;
1.1       markus    746:        TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
                    747:        ret = mkdir(name, mode);
1.10      markus    748:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    749:        send_status(id, status);
                    750:        xfree(name);
                    751: }
                    752:
                    753: void
                    754: process_rmdir(void)
                    755: {
                    756:        u_int32_t id;
                    757:        char *name;
                    758:        int ret, status;
                    759:
                    760:        id = get_int();
                    761:        name = get_string(NULL);
                    762:        TRACE("rmdir id %d name %s", id, name);
                    763:        ret = rmdir(name);
1.10      markus    764:        status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1.1       markus    765:        send_status(id, status);
                    766:        xfree(name);
                    767: }
                    768:
                    769: void
                    770: process_realpath(void)
                    771: {
                    772:        char resolvedname[MAXPATHLEN];
                    773:        u_int32_t id;
                    774:        char *path;
                    775:
                    776:        id = get_int();
                    777:        path = get_string(NULL);
1.7       markus    778:        if (path[0] == '\0') {
                    779:                xfree(path);
                    780:                path = xstrdup(".");
                    781:        }
1.1       markus    782:        TRACE("realpath id %d path %s", id, path);
                    783:        if (realpath(path, resolvedname) == NULL) {
                    784:                send_status(id, errno_to_portable(errno));
                    785:        } else {
                    786:                Stat s;
                    787:                attrib_clear(&s.attrib);
                    788:                s.name = s.long_name = resolvedname;
                    789:                send_names(id, 1, &s);
                    790:        }
                    791:        xfree(path);
                    792: }
                    793:
                    794: void
                    795: process_rename(void)
                    796: {
                    797:        u_int32_t id;
1.11      markus    798:        struct stat st;
1.1       markus    799:        char *oldpath, *newpath;
1.11      markus    800:        int ret, status = SSH2_FX_FAILURE;
1.1       markus    801:
                    802:        id = get_int();
                    803:        oldpath = get_string(NULL);
                    804:        newpath = get_string(NULL);
                    805:        TRACE("rename id %d old %s new %s", id, oldpath, newpath);
1.11      markus    806:        /* fail if 'newpath' exists */
                    807:        if (stat(newpath, &st) == -1) {
                    808:                ret = rename(oldpath, newpath);
                    809:                status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
                    810:        }
1.1       markus    811:        send_status(id, status);
                    812:        xfree(oldpath);
                    813:        xfree(newpath);
                    814: }
                    815:
1.10      markus    816: void
                    817: process_extended(void)
                    818: {
                    819:        u_int32_t id;
                    820:        char *request;
                    821:
                    822:        id = get_int();
                    823:        request = get_string(NULL);
                    824:        send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */
                    825:        xfree(request);
                    826: }
1.1       markus    827:
                    828: /* stolen from ssh-agent */
                    829:
                    830: void
                    831: process(void)
                    832: {
1.9       markus    833:        u_int msg_len;
                    834:        u_int type;
                    835:        u_char *cp;
1.1       markus    836:
                    837:        if (buffer_len(&iqueue) < 5)
                    838:                return;         /* Incomplete message. */
1.9       markus    839:        cp = (u_char *) buffer_ptr(&iqueue);
1.1       markus    840:        msg_len = GET_32BIT(cp);
                    841:        if (msg_len > 256 * 1024) {
                    842:                error("bad message ");
                    843:                exit(11);
                    844:        }
                    845:        if (buffer_len(&iqueue) < msg_len + 4)
                    846:                return;
                    847:        buffer_consume(&iqueue, 4);
                    848:        type = buffer_get_char(&iqueue);
                    849:        switch (type) {
1.10      markus    850:        case SSH2_FXP_INIT:
1.1       markus    851:                process_init();
                    852:                break;
1.10      markus    853:        case SSH2_FXP_OPEN:
1.1       markus    854:                process_open();
                    855:                break;
1.10      markus    856:        case SSH2_FXP_CLOSE:
1.1       markus    857:                process_close();
                    858:                break;
1.10      markus    859:        case SSH2_FXP_READ:
1.1       markus    860:                process_read();
                    861:                break;
1.10      markus    862:        case SSH2_FXP_WRITE:
1.1       markus    863:                process_write();
                    864:                break;
1.10      markus    865:        case SSH2_FXP_LSTAT:
1.1       markus    866:                process_lstat();
                    867:                break;
1.10      markus    868:        case SSH2_FXP_FSTAT:
1.1       markus    869:                process_fstat();
                    870:                break;
1.10      markus    871:        case SSH2_FXP_SETSTAT:
1.1       markus    872:                process_setstat();
                    873:                break;
1.10      markus    874:        case SSH2_FXP_FSETSTAT:
1.1       markus    875:                process_fsetstat();
                    876:                break;
1.10      markus    877:        case SSH2_FXP_OPENDIR:
1.1       markus    878:                process_opendir();
                    879:                break;
1.10      markus    880:        case SSH2_FXP_READDIR:
1.1       markus    881:                process_readdir();
                    882:                break;
1.10      markus    883:        case SSH2_FXP_REMOVE:
1.1       markus    884:                process_remove();
                    885:                break;
1.10      markus    886:        case SSH2_FXP_MKDIR:
1.1       markus    887:                process_mkdir();
                    888:                break;
1.10      markus    889:        case SSH2_FXP_RMDIR:
1.1       markus    890:                process_rmdir();
                    891:                break;
1.10      markus    892:        case SSH2_FXP_REALPATH:
1.1       markus    893:                process_realpath();
                    894:                break;
1.10      markus    895:        case SSH2_FXP_STAT:
1.1       markus    896:                process_stat();
                    897:                break;
1.10      markus    898:        case SSH2_FXP_RENAME:
1.1       markus    899:                process_rename();
                    900:                break;
1.10      markus    901:        case SSH2_FXP_EXTENDED:
                    902:                process_extended();
                    903:                break;
1.1       markus    904:        default:
                    905:                error("Unknown message %d", type);
                    906:                break;
                    907:        }
                    908: }
                    909:
                    910: int
                    911: main(int ac, char **av)
                    912: {
                    913:        fd_set rset, wset;
                    914:        int in, out, max;
1.5       markus    915:        ssize_t len, olen;
1.1       markus    916:
                    917:        handle_init();
1.10      markus    918:
1.11      markus    919: #ifdef DEBUG_SFTP_SERVER
1.10      markus    920:         log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1.11      markus    921: #endif
1.1       markus    922:
                    923:        in = dup(STDIN_FILENO);
                    924:        out = dup(STDOUT_FILENO);
                    925:
                    926:        max = 0;
                    927:        if (in > max)
                    928:                max = in;
                    929:        if (out > max)
                    930:                max = out;
                    931:
                    932:        buffer_init(&iqueue);
                    933:        buffer_init(&oqueue);
                    934:
                    935:        for (;;) {
                    936:                FD_ZERO(&rset);
                    937:                FD_ZERO(&wset);
                    938:
                    939:                FD_SET(in, &rset);
                    940:                olen = buffer_len(&oqueue);
                    941:                if (olen > 0)
                    942:                        FD_SET(out, &wset);
                    943:
                    944:                if (select(max+1, &rset, &wset, NULL, NULL) < 0) {
                    945:                        if (errno == EINTR)
                    946:                                continue;
                    947:                        exit(2);
                    948:                }
                    949:
                    950:                /* copy stdin to iqueue */
                    951:                if (FD_ISSET(in, &rset)) {
                    952:                        char buf[4*4096];
                    953:                        len = read(in, buf, sizeof buf);
                    954:                        if (len == 0) {
                    955:                                debug("read eof");
                    956:                                exit(0);
                    957:                        } else if (len < 0) {
                    958:                                error("read error");
                    959:                                exit(1);
                    960:                        } else {
                    961:                                buffer_append(&iqueue, buf, len);
                    962:                        }
                    963:                }
                    964:                /* send oqueue to stdout */
                    965:                if (FD_ISSET(out, &wset)) {
                    966:                        len = write(out, buffer_ptr(&oqueue), olen);
                    967:                        if (len < 0) {
                    968:                                error("write error");
                    969:                                exit(1);
                    970:                        } else {
                    971:                                buffer_consume(&oqueue, len);
                    972:                        }
                    973:                }
                    974:                /* process requests from client */
                    975:                process();
                    976:        }
                    977: }