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

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