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

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