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

Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.11

1.1       djm         1: /*
                      2:  * Copyright (c) 2001 Damien Miller.  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:
                     25: /* XXX: memleaks */
                     26: /* XXX: signed vs unsigned */
                     27: /* XXX: redesign to allow concurrent overlapped operations */
                     28: /* XXX: we use fatal too much, error may be more appropriate in places */
                     29: /* XXX: copy between two remote sites */
                     30:
                     31: #include "includes.h"
1.11    ! djm        32: RCSID("$OpenBSD: sftp-client.c,v 1.10 2001/02/14 09:46:03 djm Exp $");
1.1       djm        33:
                     34: #include "ssh.h"
                     35: #include "buffer.h"
                     36: #include "bufaux.h"
                     37: #include "getput.h"
                     38: #include "xmalloc.h"
                     39: #include "log.h"
                     40: #include "atomicio.h"
                     41: #include "pathnames.h"
                     42:
                     43: #include "sftp.h"
                     44: #include "sftp-common.h"
                     45: #include "sftp-client.h"
                     46:
                     47: /* How much data to read/write at at time during copies */
                     48: /* XXX: what should this be? */
                     49: #define COPY_SIZE      8192
                     50:
1.4       djm        51: /* Message ID */
                     52: static u_int msg_id = 1;
                     53:
1.1       djm        54: void
                     55: send_msg(int fd, Buffer *m)
                     56: {
                     57:        int mlen = buffer_len(m);
                     58:        int len;
                     59:        Buffer oqueue;
                     60:
                     61:        buffer_init(&oqueue);
                     62:        buffer_put_int(&oqueue, mlen);
                     63:        buffer_append(&oqueue, buffer_ptr(m), mlen);
                     64:        buffer_consume(m, mlen);
                     65:
                     66:        len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
                     67:        if (len <= 0)
                     68:                fatal("Couldn't send packet: %s", strerror(errno));
                     69:
                     70:        buffer_free(&oqueue);
                     71: }
                     72:
                     73: void
                     74: get_msg(int fd, Buffer *m)
                     75: {
                     76:        u_int len, msg_len;
                     77:        unsigned char buf[4096];
                     78:
                     79:        len = atomicio(read, fd, buf, 4);
                     80:        if (len != 4)
                     81:                fatal("Couldn't read packet: %s", strerror(errno));
                     82:
                     83:        msg_len = GET_32BIT(buf);
                     84:        if (msg_len > 256 * 1024)
                     85:                fatal("Received message too long %d", msg_len);
                     86:
                     87:        while (msg_len) {
                     88:                len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
                     89:                if (len <= 0)
                     90:                        fatal("Couldn't read packet: %s", strerror(errno));
                     91:
                     92:                msg_len -= len;
                     93:                buffer_append(m, buf, len);
                     94:        }
                     95: }
                     96:
                     97: void
                     98: send_string_request(int fd, u_int id, u_int code, char *s,
                     99:     u_int len)
                    100: {
                    101:        Buffer msg;
                    102:
                    103:        buffer_init(&msg);
                    104:        buffer_put_char(&msg, code);
                    105:        buffer_put_int(&msg, id);
                    106:        buffer_put_string(&msg, s, len);
                    107:        send_msg(fd, &msg);
                    108:        debug3("Sent message fd %d T:%d I:%d", fd, code, id);
                    109:        buffer_free(&msg);
                    110: }
                    111:
                    112: void
                    113: send_string_attrs_request(int fd, u_int id, u_int code, char *s,
                    114:     u_int len, Attrib *a)
                    115: {
                    116:        Buffer msg;
                    117:
                    118:        buffer_init(&msg);
                    119:        buffer_put_char(&msg, code);
                    120:        buffer_put_int(&msg, id);
                    121:        buffer_put_string(&msg, s, len);
                    122:        encode_attrib(&msg, a);
                    123:        send_msg(fd, &msg);
                    124:        debug3("Sent message fd %d T:%d I:%d", fd, code, id);
                    125:        buffer_free(&msg);
                    126: }
                    127:
                    128: u_int
                    129: get_status(int fd, int expected_id)
                    130: {
                    131:        Buffer msg;
                    132:        u_int type, id, status;
                    133:
                    134:        buffer_init(&msg);
                    135:        get_msg(fd, &msg);
                    136:        type = buffer_get_char(&msg);
                    137:        id = buffer_get_int(&msg);
                    138:
                    139:        if (id != expected_id)
                    140:                fatal("ID mismatch (%d != %d)", id, expected_id);
                    141:        if (type != SSH2_FXP_STATUS)
                    142:                fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
                    143:                    SSH2_FXP_STATUS, type);
                    144:
                    145:        status = buffer_get_int(&msg);
                    146:        buffer_free(&msg);
                    147:
                    148:        debug3("SSH2_FXP_STATUS %d", status);
                    149:
                    150:        return(status);
                    151: }
                    152:
                    153: char *
                    154: get_handle(int fd, u_int expected_id, u_int *len)
                    155: {
                    156:        Buffer msg;
                    157:        u_int type, id;
                    158:        char *handle;
                    159:
                    160:        buffer_init(&msg);
                    161:        get_msg(fd, &msg);
                    162:        type = buffer_get_char(&msg);
                    163:        id = buffer_get_int(&msg);
                    164:
                    165:        if (id != expected_id)
                    166:                fatal("ID mismatch (%d != %d)", id, expected_id);
                    167:        if (type == SSH2_FXP_STATUS) {
                    168:                int status = buffer_get_int(&msg);
                    169:
                    170:                error("Couldn't get handle: %s", fx2txt(status));
                    171:                return(NULL);
                    172:        } else if (type != SSH2_FXP_HANDLE)
                    173:                fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
                    174:                    SSH2_FXP_HANDLE, type);
                    175:
                    176:        handle = buffer_get_string(&msg, len);
                    177:        buffer_free(&msg);
                    178:
                    179:        return(handle);
                    180: }
                    181:
                    182: Attrib *
                    183: get_decode_stat(int fd, u_int expected_id)
                    184: {
                    185:        Buffer msg;
                    186:        u_int type, id;
                    187:        Attrib *a;
                    188:
                    189:        buffer_init(&msg);
                    190:        get_msg(fd, &msg);
                    191:
                    192:        type = buffer_get_char(&msg);
                    193:        id = buffer_get_int(&msg);
                    194:
                    195:        debug3("Received stat reply T:%d I:%d", type, id);
                    196:        if (id != expected_id)
                    197:                fatal("ID mismatch (%d != %d)", id, expected_id);
                    198:        if (type == SSH2_FXP_STATUS) {
                    199:                int status = buffer_get_int(&msg);
                    200:
                    201:                error("Couldn't stat remote file: %s", fx2txt(status));
                    202:                return(NULL);
                    203:        } else if (type != SSH2_FXP_ATTRS) {
                    204:                fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
                    205:                    SSH2_FXP_ATTRS, type);
                    206:        }
                    207:        a = decode_attrib(&msg);
                    208:        buffer_free(&msg);
                    209:
                    210:        return(a);
                    211: }
                    212:
                    213: int
                    214: do_init(int fd_in, int fd_out)
                    215: {
                    216:        int type, version;
                    217:        Buffer msg;
                    218:
                    219:        buffer_init(&msg);
                    220:        buffer_put_char(&msg, SSH2_FXP_INIT);
                    221:        buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
                    222:        send_msg(fd_out, &msg);
                    223:
                    224:        buffer_clear(&msg);
                    225:
                    226:        get_msg(fd_in, &msg);
                    227:
1.3       stevesk   228:        /* Expecting a VERSION reply */
1.1       djm       229:        if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
                    230:                error("Invalid packet back from SSH2_FXP_INIT (type %d)",
                    231:                    type);
                    232:                buffer_free(&msg);
                    233:                return(-1);
                    234:        }
                    235:        version = buffer_get_int(&msg);
                    236:
                    237:        debug2("Remote version: %d", version);
                    238:
                    239:        /* Check for extensions */
                    240:        while (buffer_len(&msg) > 0) {
                    241:                char *name = buffer_get_string(&msg, NULL);
                    242:                char *value = buffer_get_string(&msg, NULL);
                    243:
                    244:                debug2("Init extension: \"%s\"", name);
                    245:                xfree(name);
                    246:                xfree(value);
                    247:        }
                    248:
                    249:        buffer_free(&msg);
1.11    ! djm       250:
        !           251:        return(version);
1.1       djm       252: }
                    253:
                    254: int
                    255: do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
                    256: {
                    257:        u_int id, status;
                    258:        Buffer msg;
                    259:
                    260:        buffer_init(&msg);
                    261:
1.4       djm       262:        id = msg_id++;
1.1       djm       263:        buffer_put_char(&msg, SSH2_FXP_CLOSE);
                    264:        buffer_put_int(&msg, id);
                    265:        buffer_put_string(&msg, handle, handle_len);
                    266:        send_msg(fd_out, &msg);
                    267:        debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
                    268:
                    269:        status = get_status(fd_in, id);
                    270:        if (status != SSH2_FX_OK)
                    271:                error("Couldn't close file: %s", fx2txt(status));
                    272:
                    273:        buffer_free(&msg);
                    274:
                    275:        return(status);
                    276: }
                    277:
                    278: int
                    279: do_ls(int fd_in, int fd_out, char *path)
                    280: {
                    281:        Buffer msg;
                    282:        u_int type, id, handle_len, i, expected_id;
                    283:        char *handle;
                    284:
1.4       djm       285:        id = msg_id++;
1.1       djm       286:
                    287:        buffer_init(&msg);
                    288:        buffer_put_char(&msg, SSH2_FXP_OPENDIR);
                    289:        buffer_put_int(&msg, id);
                    290:        buffer_put_cstring(&msg, path);
                    291:        send_msg(fd_out, &msg);
                    292:
                    293:        buffer_clear(&msg);
                    294:
                    295:        handle = get_handle(fd_in, id, &handle_len);
                    296:        if (handle == NULL)
                    297:                return(-1);
                    298:
                    299:        for(;;) {
                    300:                int count;
                    301:
1.4       djm       302:                id = expected_id = msg_id++;
1.1       djm       303:
                    304:                debug3("Sending SSH2_FXP_READDIR I:%d", id);
                    305:
                    306:                buffer_clear(&msg);
                    307:                buffer_put_char(&msg, SSH2_FXP_READDIR);
                    308:                buffer_put_int(&msg, id);
                    309:                buffer_put_string(&msg, handle, handle_len);
                    310:                send_msg(fd_out, &msg);
                    311:
                    312:                buffer_clear(&msg);
                    313:
                    314:                get_msg(fd_in, &msg);
                    315:
                    316:                type = buffer_get_char(&msg);
                    317:                id = buffer_get_int(&msg);
                    318:
                    319:                debug3("Received reply T:%d I:%d", type, id);
                    320:
                    321:                if (id != expected_id)
                    322:                        fatal("ID mismatch (%d != %d)", id, expected_id);
                    323:
                    324:                if (type == SSH2_FXP_STATUS) {
                    325:                        int status = buffer_get_int(&msg);
                    326:
                    327:                        debug3("Received SSH2_FXP_STATUS %d", status);
                    328:
                    329:                        if (status == SSH2_FX_EOF) {
                    330:                                break;
                    331:                        } else {
                    332:                                error("Couldn't read directory: %s",
                    333:                                    fx2txt(status));
                    334:                                do_close(fd_in, fd_out, handle, handle_len);
1.9       djm       335:                                return(status);
1.1       djm       336:                        }
                    337:                } else if (type != SSH2_FXP_NAME)
                    338:                        fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
                    339:                            SSH2_FXP_NAME, type);
                    340:
                    341:                count = buffer_get_int(&msg);
1.7       markus    342:                if (count == 0)
                    343:                        break;
1.8       stevesk   344:                debug3("Received %d SSH2_FXP_NAME responses", count);
1.1       djm       345:                for(i = 0; i < count; i++) {
                    346:                        char *filename, *longname;
                    347:                        Attrib *a;
                    348:
                    349:                        filename = buffer_get_string(&msg, NULL);
                    350:                        longname = buffer_get_string(&msg, NULL);
                    351:                        a = decode_attrib(&msg);
                    352:
                    353:                        printf("%s\n", longname);
                    354:
                    355:                        xfree(filename);
                    356:                        xfree(longname);
                    357:                }
                    358:        }
                    359:
                    360:        buffer_free(&msg);
                    361:        do_close(fd_in, fd_out, handle, handle_len);
                    362:        xfree(handle);
                    363:
                    364:        return(0);
                    365: }
                    366:
                    367: int
                    368: do_rm(int fd_in, int fd_out, char *path)
                    369: {
                    370:        u_int status, id;
                    371:
                    372:        debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
                    373:
1.4       djm       374:        id = msg_id++;
1.1       djm       375:        send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
                    376:        status = get_status(fd_in, id);
                    377:        if (status != SSH2_FX_OK)
                    378:                error("Couldn't delete file: %s", fx2txt(status));
                    379:        return(status);
                    380: }
                    381:
                    382: int
                    383: do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
                    384: {
                    385:        u_int status, id;
                    386:
1.4       djm       387:        id = msg_id++;
1.1       djm       388:        send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
                    389:            strlen(path), a);
                    390:
                    391:        status = get_status(fd_in, id);
                    392:        if (status != SSH2_FX_OK)
                    393:                error("Couldn't create directory: %s", fx2txt(status));
                    394:
                    395:        return(status);
                    396: }
                    397:
                    398: int
                    399: do_rmdir(int fd_in, int fd_out, char *path)
                    400: {
                    401:        u_int status, id;
                    402:
1.4       djm       403:        id = msg_id++;
1.1       djm       404:        send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
                    405:
                    406:        status = get_status(fd_in, id);
                    407:        if (status != SSH2_FX_OK)
                    408:                error("Couldn't remove directory: %s", fx2txt(status));
                    409:
                    410:        return(status);
                    411: }
                    412:
                    413: Attrib *
                    414: do_stat(int fd_in, int fd_out, char *path)
                    415: {
                    416:        u_int id;
                    417:
1.4       djm       418:        id = msg_id++;
1.1       djm       419:        send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
                    420:        return(get_decode_stat(fd_in, id));
                    421: }
                    422:
                    423: Attrib *
                    424: do_lstat(int fd_in, int fd_out, char *path)
                    425: {
                    426:        u_int id;
                    427:
1.4       djm       428:        id = msg_id++;
1.1       djm       429:        send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
                    430:        return(get_decode_stat(fd_in, id));
                    431: }
                    432:
                    433: Attrib *
                    434: do_fstat(int fd_in, int fd_out, char *handle,
                    435:     u_int handle_len)
                    436: {
                    437:        u_int id;
                    438:
1.4       djm       439:        id = msg_id++;
1.1       djm       440:        send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
                    441:        return(get_decode_stat(fd_in, id));
                    442: }
                    443:
                    444: int
                    445: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
                    446: {
                    447:        u_int status, id;
                    448:
1.4       djm       449:        id = msg_id++;
1.1       djm       450:        send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
                    451:            strlen(path), a);
                    452:
                    453:        status = get_status(fd_in, id);
                    454:        if (status != SSH2_FX_OK)
                    455:                error("Couldn't setstat on \"%s\": %s", path,
                    456:                    fx2txt(status));
                    457:
                    458:        return(status);
                    459: }
                    460:
                    461: int
                    462: do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
                    463:     Attrib *a)
                    464: {
                    465:        u_int status, id;
                    466:
1.4       djm       467:        id = msg_id++;
1.1       djm       468:        send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
                    469:            handle_len, a);
                    470:
                    471:        status = get_status(fd_in, id);
                    472:        if (status != SSH2_FX_OK)
                    473:                error("Couldn't fsetstat: %s", fx2txt(status));
                    474:
                    475:        return(status);
                    476: }
                    477:
                    478: char *
                    479: do_realpath(int fd_in, int fd_out, char *path)
                    480: {
                    481:        Buffer msg;
                    482:        u_int type, expected_id, count, id;
                    483:        char *filename, *longname;
                    484:        Attrib *a;
                    485:
1.4       djm       486:        expected_id = id = msg_id++;
1.11    ! djm       487:        send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
1.1       djm       488:
                    489:        buffer_init(&msg);
                    490:
                    491:        get_msg(fd_in, &msg);
                    492:        type = buffer_get_char(&msg);
                    493:        id = buffer_get_int(&msg);
                    494:
                    495:        if (id != expected_id)
                    496:                fatal("ID mismatch (%d != %d)", id, expected_id);
                    497:
                    498:        if (type == SSH2_FXP_STATUS) {
                    499:                u_int status = buffer_get_int(&msg);
                    500:
                    501:                error("Couldn't canonicalise: %s", fx2txt(status));
                    502:                return(NULL);
                    503:        } else if (type != SSH2_FXP_NAME)
                    504:                fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
                    505:                    SSH2_FXP_NAME, type);
                    506:
                    507:        count = buffer_get_int(&msg);
                    508:        if (count != 1)
                    509:                fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
                    510:
                    511:        filename = buffer_get_string(&msg, NULL);
                    512:        longname = buffer_get_string(&msg, NULL);
                    513:        a = decode_attrib(&msg);
                    514:
                    515:        debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
                    516:
                    517:        xfree(longname);
                    518:
                    519:        buffer_free(&msg);
                    520:
                    521:        return(filename);
                    522: }
                    523:
                    524: int
                    525: do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
                    526: {
                    527:        Buffer msg;
                    528:        u_int status, id;
                    529:
                    530:        buffer_init(&msg);
                    531:
                    532:        /* Send rename request */
1.4       djm       533:        id = msg_id++;
1.1       djm       534:        buffer_put_char(&msg, SSH2_FXP_RENAME);
                    535:        buffer_put_int(&msg, id);
                    536:        buffer_put_cstring(&msg, oldpath);
                    537:        buffer_put_cstring(&msg, newpath);
                    538:        send_msg(fd_out, &msg);
                    539:        debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
                    540:            newpath);
                    541:        buffer_free(&msg);
                    542:
                    543:        status = get_status(fd_in, id);
                    544:        if (status != SSH2_FX_OK)
                    545:                error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
                    546:                    fx2txt(status));
                    547:
                    548:        return(status);
1.11    ! djm       549: }
        !           550:
        !           551: int
        !           552: do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
        !           553: {
        !           554:        Buffer msg;
        !           555:        u_int status, id;
        !           556:
        !           557:        buffer_init(&msg);
        !           558:
        !           559:        /* Send rename request */
        !           560:        id = msg_id++;
        !           561:        buffer_put_char(&msg, SSH2_FXP_SYMLINK);
        !           562:        buffer_put_int(&msg, id);
        !           563:        buffer_put_cstring(&msg, oldpath);
        !           564:        buffer_put_cstring(&msg, newpath);
        !           565:        send_msg(fd_out, &msg);
        !           566:        debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
        !           567:            newpath);
        !           568:        buffer_free(&msg);
        !           569:
        !           570:        status = get_status(fd_in, id);
        !           571:        if (status != SSH2_FX_OK)
        !           572:                error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
        !           573:                    fx2txt(status));
        !           574:
        !           575:        return(status);
        !           576: }
        !           577:
        !           578: char *
        !           579: do_readlink(int fd_in, int fd_out, char *path)
        !           580: {
        !           581:        Buffer msg;
        !           582:        u_int type, expected_id, count, id;
        !           583:        char *filename, *longname;
        !           584:        Attrib *a;
        !           585:
        !           586:        expected_id = id = msg_id++;
        !           587:        send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
        !           588:
        !           589:        buffer_init(&msg);
        !           590:
        !           591:        get_msg(fd_in, &msg);
        !           592:        type = buffer_get_char(&msg);
        !           593:        id = buffer_get_int(&msg);
        !           594:
        !           595:        if (id != expected_id)
        !           596:                fatal("ID mismatch (%d != %d)", id, expected_id);
        !           597:
        !           598:        if (type == SSH2_FXP_STATUS) {
        !           599:                u_int status = buffer_get_int(&msg);
        !           600:
        !           601:                error("Couldn't readlink: %s", fx2txt(status));
        !           602:                return(NULL);
        !           603:        } else if (type != SSH2_FXP_NAME)
        !           604:                fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
        !           605:                    SSH2_FXP_NAME, type);
        !           606:
        !           607:        count = buffer_get_int(&msg);
        !           608:        if (count != 1)
        !           609:                fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
        !           610:
        !           611:        filename = buffer_get_string(&msg, NULL);
        !           612:        longname = buffer_get_string(&msg, NULL);
        !           613:        a = decode_attrib(&msg);
        !           614:
        !           615:        debug3("SSH_FXP_READLINK %s -> %s", path, filename);
        !           616:
        !           617:        xfree(longname);
        !           618:
        !           619:        buffer_free(&msg);
        !           620:
        !           621:        return(filename);
1.1       djm       622: }
                    623:
                    624: int
                    625: do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                    626:     int pflag)
                    627: {
                    628:        int local_fd;
                    629:        u_int expected_id, handle_len, mode, type, id;
                    630:        u_int64_t offset;
                    631:        char *handle;
                    632:        Buffer msg;
                    633:        Attrib junk, *a;
1.5       djm       634:        int status;
1.1       djm       635:
                    636:        a = do_stat(fd_in, fd_out, remote_path);
                    637:        if (a == NULL)
                    638:                return(-1);
                    639:
                    640:        /* XXX: should we preserve set[ug]id? */
                    641:        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
                    642:                mode = S_IWRITE | (a->perm & 0777);
                    643:        else
                    644:                mode = 0666;
                    645:
                    646:        local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
                    647:        if (local_fd == -1) {
                    648:                error("Couldn't open local file \"%s\" for writing: %s",
                    649:                    local_path, strerror(errno));
                    650:                return(errno);
                    651:        }
                    652:
                    653:        buffer_init(&msg);
                    654:
                    655:        /* Send open request */
1.4       djm       656:        id = msg_id++;
1.1       djm       657:        buffer_put_char(&msg, SSH2_FXP_OPEN);
                    658:        buffer_put_int(&msg, id);
                    659:        buffer_put_cstring(&msg, remote_path);
                    660:        buffer_put_int(&msg, SSH2_FXF_READ);
                    661:        attrib_clear(&junk); /* Send empty attributes */
                    662:        encode_attrib(&msg, &junk);
                    663:        send_msg(fd_out, &msg);
                    664:        debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
                    665:
                    666:        handle = get_handle(fd_in, id, &handle_len);
                    667:        if (handle == NULL) {
                    668:                buffer_free(&msg);
                    669:                close(local_fd);
                    670:                return(-1);
                    671:        }
                    672:
                    673:        /* Read from remote and write to local */
                    674:        offset = 0;
                    675:        for(;;) {
                    676:                u_int len;
                    677:                char *data;
                    678:
1.4       djm       679:                id = expected_id = msg_id++;
1.1       djm       680:
                    681:                buffer_clear(&msg);
                    682:                buffer_put_char(&msg, SSH2_FXP_READ);
                    683:                buffer_put_int(&msg, id);
                    684:                buffer_put_string(&msg, handle, handle_len);
                    685:                buffer_put_int64(&msg, offset);
                    686:                buffer_put_int(&msg, COPY_SIZE);
                    687:                send_msg(fd_out, &msg);
                    688:                debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
1.2       deraadt   689:                    id, (unsigned long long)offset, COPY_SIZE);
1.1       djm       690:
                    691:                buffer_clear(&msg);
                    692:
                    693:                get_msg(fd_in, &msg);
                    694:                type = buffer_get_char(&msg);
                    695:                id = buffer_get_int(&msg);
                    696:                debug3("Received reply T:%d I:%d", type, id);
                    697:                if (id != expected_id)
                    698:                        fatal("ID mismatch (%d != %d)", id, expected_id);
                    699:                if (type == SSH2_FXP_STATUS) {
1.5       djm       700:                        status = buffer_get_int(&msg);
1.1       djm       701:
                    702:                        if (status == SSH2_FX_EOF)
                    703:                                break;
                    704:                        else {
                    705:                                error("Couldn't read from remote "
                    706:                                    "file \"%s\" : %s", remote_path,
                    707:                                     fx2txt(status));
                    708:                                do_close(fd_in, fd_out, handle, handle_len);
1.5       djm       709:                                goto done;
1.1       djm       710:                        }
                    711:                } else if (type != SSH2_FXP_DATA) {
                    712:                        fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
                    713:                            SSH2_FXP_DATA, type);
                    714:                }
                    715:
                    716:                data = buffer_get_string(&msg, &len);
                    717:                if (len > COPY_SIZE)
                    718:                        fatal("Received more data than asked for %d > %d",
                    719:                            len, COPY_SIZE);
                    720:
1.6       itojun    721:                debug3("In read loop, got %d offset %llu", len,
1.2       deraadt   722:                    (unsigned long long)offset);
1.1       djm       723:                if (atomicio(write, local_fd, data, len) != len) {
                    724:                        error("Couldn't write to \"%s\": %s", local_path,
                    725:                            strerror(errno));
                    726:                        do_close(fd_in, fd_out, handle, handle_len);
1.5       djm       727:                        status = -1;
1.1       djm       728:                        xfree(data);
1.5       djm       729:                        goto done;
1.1       djm       730:                }
                    731:
                    732:                offset += len;
                    733:                xfree(data);
                    734:        }
1.5       djm       735:        status = do_close(fd_in, fd_out, handle, handle_len);
                    736:
1.10      djm       737:        /* Override umask and utimes if asked */
                    738:        if (pflag && fchmod(local_fd, mode) == -1)
                    739:                error("Couldn't set mode on \"%s\": %s", local_path,
                    740:                    strerror(errno));
                    741:        if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
                    742:                struct timeval tv[2];
                    743:                tv[0].tv_sec = a->atime;
                    744:                tv[1].tv_sec = a->mtime;
                    745:                tv[0].tv_usec = tv[1].tv_usec = 0;
                    746:                if (utimes(local_path, tv) == -1)
                    747:                        error("Can't set times on \"%s\": %s", local_path,
                    748:                            strerror(errno));
                    749:        }
                    750:
1.5       djm       751: done:
                    752:        close(local_fd);
                    753:        buffer_free(&msg);
1.1       djm       754:        xfree(handle);
1.5       djm       755:        return status;
1.1       djm       756: }
                    757:
                    758: int
                    759: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
                    760:     int pflag)
                    761: {
                    762:        int local_fd;
                    763:        u_int handle_len, id;
                    764:        u_int64_t offset;
                    765:        char *handle;
                    766:        Buffer msg;
                    767:        struct stat sb;
                    768:        Attrib a;
1.5       djm       769:        int status;
1.1       djm       770:
                    771:        if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
                    772:                error("Couldn't open local file \"%s\" for reading: %s",
                    773:                    local_path, strerror(errno));
                    774:                return(-1);
                    775:        }
                    776:        if (fstat(local_fd, &sb) == -1) {
                    777:                error("Couldn't fstat local file \"%s\": %s",
                    778:                    local_path, strerror(errno));
                    779:                close(local_fd);
                    780:                return(-1);
                    781:        }
                    782:        stat_to_attrib(&sb, &a);
                    783:
                    784:        a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
                    785:        a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
                    786:        a.perm &= 0777;
                    787:        if (!pflag)
                    788:                a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
                    789:
                    790:        buffer_init(&msg);
                    791:
                    792:        /* Send open request */
1.4       djm       793:        id = msg_id++;
1.1       djm       794:        buffer_put_char(&msg, SSH2_FXP_OPEN);
                    795:        buffer_put_int(&msg, id);
                    796:        buffer_put_cstring(&msg, remote_path);
                    797:        buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
                    798:        encode_attrib(&msg, &a);
                    799:        send_msg(fd_out, &msg);
                    800:        debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
                    801:
                    802:        buffer_clear(&msg);
                    803:
                    804:        handle = get_handle(fd_in, id, &handle_len);
                    805:        if (handle == NULL) {
                    806:                close(local_fd);
                    807:                buffer_free(&msg);
                    808:                return(-1);
                    809:        }
                    810:
                    811:        /* Read from local and write to remote */
                    812:        offset = 0;
                    813:        for(;;) {
                    814:                int len;
                    815:                char data[COPY_SIZE];
                    816:
                    817:                /*
                    818:                 * Can't use atomicio here because it returns 0 on EOF, thus losing
                    819:                 * the last block of the file
                    820:                 */
                    821:                do
                    822:                        len = read(local_fd, data, COPY_SIZE);
                    823:                while ((len == -1) && (errno == EINTR || errno == EAGAIN));
                    824:
                    825:                if (len == -1)
                    826:                        fatal("Couldn't read from \"%s\": %s", local_path,
                    827:                            strerror(errno));
                    828:                if (len == 0)
                    829:                        break;
                    830:
                    831:                buffer_clear(&msg);
                    832:                buffer_put_char(&msg, SSH2_FXP_WRITE);
                    833:                buffer_put_int(&msg, ++id);
                    834:                buffer_put_string(&msg, handle, handle_len);
                    835:                buffer_put_int64(&msg, offset);
                    836:                buffer_put_string(&msg, data, len);
                    837:                send_msg(fd_out, &msg);
                    838:                debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2       deraadt   839:                    id, (unsigned long long)offset, len);
1.1       djm       840:
                    841:                status = get_status(fd_in, id);
                    842:                if (status != SSH2_FX_OK) {
                    843:                        error("Couldn't write to remote file \"%s\": %s",
                    844:                            remote_path, fx2txt(status));
                    845:                        do_close(fd_in, fd_out, handle, handle_len);
                    846:                        close(local_fd);
1.5       djm       847:                        goto done;
1.1       djm       848:                }
1.2       deraadt   849:                debug3("In write loop, got %d offset %llu", len,
                    850:                    (unsigned long long)offset);
1.1       djm       851:
                    852:                offset += len;
                    853:        }
                    854:
                    855:        if (close(local_fd) == -1) {
                    856:                error("Couldn't close local file \"%s\": %s", local_path,
                    857:                    strerror(errno));
                    858:                do_close(fd_in, fd_out, handle, handle_len);
1.5       djm       859:                status = -1;
                    860:                goto done;
1.1       djm       861:        }
                    862:
1.10      djm       863:        /* Override umask and utimes if asked */
                    864:        if (pflag)
                    865:                do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
                    866:
1.5       djm       867:        status = do_close(fd_in, fd_out, handle, handle_len);
                    868:
                    869: done:
                    870:        xfree(handle);
                    871:        buffer_free(&msg);
                    872:        return status;
1.1       djm       873: }