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

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.14    ! djm        32: RCSID("$OpenBSD: sftp-client.c,v 1.13 2001/03/14 08:57:14 markus 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 *
1.14    ! djm       183: get_decode_stat(int fd, u_int expected_id, int quiet)
1.1       djm       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:
1.14    ! djm       201:                if (quiet)
        !           202:                        debug("Couldn't stat remote file: %s", fx2txt(status));
        !           203:                else
        !           204:                        error("Couldn't stat remote file: %s", fx2txt(status));
1.1       djm       205:                return(NULL);
                    206:        } else if (type != SSH2_FXP_ATTRS) {
                    207:                fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
                    208:                    SSH2_FXP_ATTRS, type);
                    209:        }
                    210:        a = decode_attrib(&msg);
                    211:        buffer_free(&msg);
                    212:
                    213:        return(a);
                    214: }
                    215:
                    216: int
                    217: do_init(int fd_in, int fd_out)
                    218: {
                    219:        int type, version;
                    220:        Buffer msg;
                    221:
                    222:        buffer_init(&msg);
                    223:        buffer_put_char(&msg, SSH2_FXP_INIT);
                    224:        buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
                    225:        send_msg(fd_out, &msg);
                    226:
                    227:        buffer_clear(&msg);
                    228:
                    229:        get_msg(fd_in, &msg);
                    230:
1.3       stevesk   231:        /* Expecting a VERSION reply */
1.1       djm       232:        if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
                    233:                error("Invalid packet back from SSH2_FXP_INIT (type %d)",
                    234:                    type);
                    235:                buffer_free(&msg);
                    236:                return(-1);
                    237:        }
                    238:        version = buffer_get_int(&msg);
                    239:
                    240:        debug2("Remote version: %d", version);
                    241:
                    242:        /* Check for extensions */
                    243:        while (buffer_len(&msg) > 0) {
                    244:                char *name = buffer_get_string(&msg, NULL);
                    245:                char *value = buffer_get_string(&msg, NULL);
                    246:
                    247:                debug2("Init extension: \"%s\"", name);
                    248:                xfree(name);
                    249:                xfree(value);
                    250:        }
                    251:
                    252:        buffer_free(&msg);
1.11      djm       253:
                    254:        return(version);
1.1       djm       255: }
                    256:
                    257: int
                    258: do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
                    259: {
                    260:        u_int id, status;
                    261:        Buffer msg;
                    262:
                    263:        buffer_init(&msg);
                    264:
1.4       djm       265:        id = msg_id++;
1.1       djm       266:        buffer_put_char(&msg, SSH2_FXP_CLOSE);
                    267:        buffer_put_int(&msg, id);
                    268:        buffer_put_string(&msg, handle, handle_len);
                    269:        send_msg(fd_out, &msg);
                    270:        debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
                    271:
                    272:        status = get_status(fd_in, id);
                    273:        if (status != SSH2_FX_OK)
                    274:                error("Couldn't close file: %s", fx2txt(status));
                    275:
                    276:        buffer_free(&msg);
                    277:
                    278:        return(status);
                    279: }
                    280:
1.12      djm       281:
1.1       djm       282: int
1.12      djm       283: do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
                    284:     SFTP_DIRENT ***dir)
1.1       djm       285: {
                    286:        Buffer msg;
1.13      markus    287:        u_int type, id, handle_len, i, expected_id, ents = 0;
1.1       djm       288:        char *handle;
                    289:
1.4       djm       290:        id = msg_id++;
1.1       djm       291:
                    292:        buffer_init(&msg);
                    293:        buffer_put_char(&msg, SSH2_FXP_OPENDIR);
                    294:        buffer_put_int(&msg, id);
                    295:        buffer_put_cstring(&msg, path);
                    296:        send_msg(fd_out, &msg);
                    297:
                    298:        buffer_clear(&msg);
                    299:
                    300:        handle = get_handle(fd_in, id, &handle_len);
                    301:        if (handle == NULL)
                    302:                return(-1);
                    303:
1.12      djm       304:        if (dir) {
                    305:                ents = 0;
                    306:                *dir = xmalloc(sizeof(**dir));
                    307:                (*dir)[0] = NULL;
                    308:        }
                    309:
                    310:
1.1       djm       311:        for(;;) {
                    312:                int count;
                    313:
1.4       djm       314:                id = expected_id = msg_id++;
1.1       djm       315:
                    316:                debug3("Sending SSH2_FXP_READDIR I:%d", id);
                    317:
                    318:                buffer_clear(&msg);
                    319:                buffer_put_char(&msg, SSH2_FXP_READDIR);
                    320:                buffer_put_int(&msg, id);
                    321:                buffer_put_string(&msg, handle, handle_len);
                    322:                send_msg(fd_out, &msg);
                    323:
                    324:                buffer_clear(&msg);
                    325:
                    326:                get_msg(fd_in, &msg);
                    327:
                    328:                type = buffer_get_char(&msg);
                    329:                id = buffer_get_int(&msg);
                    330:
                    331:                debug3("Received reply T:%d I:%d", type, id);
                    332:
                    333:                if (id != expected_id)
                    334:                        fatal("ID mismatch (%d != %d)", id, expected_id);
                    335:
                    336:                if (type == SSH2_FXP_STATUS) {
                    337:                        int status = buffer_get_int(&msg);
                    338:
                    339:                        debug3("Received SSH2_FXP_STATUS %d", status);
                    340:
                    341:                        if (status == SSH2_FX_EOF) {
                    342:                                break;
                    343:                        } else {
                    344:                                error("Couldn't read directory: %s",
                    345:                                    fx2txt(status));
                    346:                                do_close(fd_in, fd_out, handle, handle_len);
1.9       djm       347:                                return(status);
1.1       djm       348:                        }
                    349:                } else if (type != SSH2_FXP_NAME)
                    350:                        fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
                    351:                            SSH2_FXP_NAME, type);
                    352:
                    353:                count = buffer_get_int(&msg);
1.7       markus    354:                if (count == 0)
                    355:                        break;
1.8       stevesk   356:                debug3("Received %d SSH2_FXP_NAME responses", count);
1.1       djm       357:                for(i = 0; i < count; i++) {
                    358:                        char *filename, *longname;
                    359:                        Attrib *a;
                    360:
                    361:                        filename = buffer_get_string(&msg, NULL);
                    362:                        longname = buffer_get_string(&msg, NULL);
                    363:                        a = decode_attrib(&msg);
                    364:
1.12      djm       365:                        if (printflag)
                    366:                                printf("%s\n", longname);
                    367:
                    368:                        if (dir) {
                    369:                                *dir = xrealloc(*dir, sizeof(**dir) *
                    370:                                    (ents + 2));
                    371:                                (*dir)[ents] = xmalloc(sizeof(***dir));
                    372:                                (*dir)[ents]->filename = xstrdup(filename);
                    373:                                (*dir)[ents]->longname = xstrdup(longname);
                    374:                                memcpy(&(*dir)[ents]->a, a, sizeof(*a));
                    375:                                (*dir)[++ents] = NULL;
                    376:                        }
1.1       djm       377:
                    378:                        xfree(filename);
                    379:                        xfree(longname);
                    380:                }
                    381:        }
                    382:
                    383:        buffer_free(&msg);
                    384:        do_close(fd_in, fd_out, handle, handle_len);
                    385:        xfree(handle);
                    386:
                    387:        return(0);
                    388: }
                    389:
                    390: int
1.12      djm       391: do_ls(int fd_in, int fd_out, char *path)
                    392: {
                    393:        return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
                    394: }
                    395:
                    396: int
                    397: do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
                    398: {
                    399:        return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
                    400: }
                    401:
                    402: void free_sftp_dirents(SFTP_DIRENT **s)
                    403: {
                    404:        int i;
                    405:
                    406:        for(i = 0; s[i]; i++) {
                    407:                xfree(s[i]->filename);
                    408:                xfree(s[i]->longname);
                    409:                xfree(s[i]);
                    410:        }
                    411:        xfree(s);
                    412: }
                    413:
                    414: int
1.1       djm       415: do_rm(int fd_in, int fd_out, char *path)
                    416: {
                    417:        u_int status, id;
                    418:
                    419:        debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
                    420:
1.4       djm       421:        id = msg_id++;
1.1       djm       422:        send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
                    423:        status = get_status(fd_in, id);
                    424:        if (status != SSH2_FX_OK)
                    425:                error("Couldn't delete file: %s", fx2txt(status));
                    426:        return(status);
                    427: }
                    428:
                    429: int
                    430: do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
                    431: {
                    432:        u_int status, id;
                    433:
1.4       djm       434:        id = msg_id++;
1.1       djm       435:        send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
                    436:            strlen(path), a);
                    437:
                    438:        status = get_status(fd_in, id);
                    439:        if (status != SSH2_FX_OK)
                    440:                error("Couldn't create directory: %s", fx2txt(status));
                    441:
                    442:        return(status);
                    443: }
                    444:
                    445: int
                    446: do_rmdir(int fd_in, int fd_out, char *path)
                    447: {
                    448:        u_int status, id;
                    449:
1.4       djm       450:        id = msg_id++;
1.1       djm       451:        send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
                    452:
                    453:        status = get_status(fd_in, id);
                    454:        if (status != SSH2_FX_OK)
                    455:                error("Couldn't remove directory: %s", fx2txt(status));
                    456:
                    457:        return(status);
                    458: }
                    459:
                    460: Attrib *
1.14    ! djm       461: do_stat(int fd_in, int fd_out, char *path, int quiet)
1.1       djm       462: {
                    463:        u_int id;
                    464:
1.4       djm       465:        id = msg_id++;
1.1       djm       466:        send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
1.14    ! djm       467:        return(get_decode_stat(fd_in, id, quiet));
1.1       djm       468: }
                    469:
                    470: Attrib *
1.14    ! djm       471: do_lstat(int fd_in, int fd_out, char *path, int quiet)
1.1       djm       472: {
                    473:        u_int id;
                    474:
1.4       djm       475:        id = msg_id++;
1.1       djm       476:        send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
1.14    ! djm       477:        return(get_decode_stat(fd_in, id, quiet));
1.1       djm       478: }
                    479:
                    480: Attrib *
1.14    ! djm       481: do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
1.1       djm       482: {
                    483:        u_int id;
                    484:
1.4       djm       485:        id = msg_id++;
1.1       djm       486:        send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
1.14    ! djm       487:        return(get_decode_stat(fd_in, id, quiet));
1.1       djm       488: }
                    489:
                    490: int
                    491: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
                    492: {
                    493:        u_int status, id;
                    494:
1.4       djm       495:        id = msg_id++;
1.1       djm       496:        send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
                    497:            strlen(path), a);
                    498:
                    499:        status = get_status(fd_in, id);
                    500:        if (status != SSH2_FX_OK)
                    501:                error("Couldn't setstat on \"%s\": %s", path,
                    502:                    fx2txt(status));
                    503:
                    504:        return(status);
                    505: }
                    506:
                    507: int
                    508: do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
                    509:     Attrib *a)
                    510: {
                    511:        u_int status, id;
                    512:
1.4       djm       513:        id = msg_id++;
1.1       djm       514:        send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
                    515:            handle_len, a);
                    516:
                    517:        status = get_status(fd_in, id);
                    518:        if (status != SSH2_FX_OK)
                    519:                error("Couldn't fsetstat: %s", fx2txt(status));
                    520:
                    521:        return(status);
                    522: }
                    523:
                    524: char *
                    525: do_realpath(int fd_in, int fd_out, char *path)
                    526: {
                    527:        Buffer msg;
                    528:        u_int type, expected_id, count, id;
                    529:        char *filename, *longname;
                    530:        Attrib *a;
                    531:
1.4       djm       532:        expected_id = id = msg_id++;
1.11      djm       533:        send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
1.1       djm       534:
                    535:        buffer_init(&msg);
                    536:
                    537:        get_msg(fd_in, &msg);
                    538:        type = buffer_get_char(&msg);
                    539:        id = buffer_get_int(&msg);
                    540:
                    541:        if (id != expected_id)
                    542:                fatal("ID mismatch (%d != %d)", id, expected_id);
                    543:
                    544:        if (type == SSH2_FXP_STATUS) {
                    545:                u_int status = buffer_get_int(&msg);
                    546:
                    547:                error("Couldn't canonicalise: %s", fx2txt(status));
                    548:                return(NULL);
                    549:        } else if (type != SSH2_FXP_NAME)
                    550:                fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
                    551:                    SSH2_FXP_NAME, type);
                    552:
                    553:        count = buffer_get_int(&msg);
                    554:        if (count != 1)
                    555:                fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
                    556:
                    557:        filename = buffer_get_string(&msg, NULL);
                    558:        longname = buffer_get_string(&msg, NULL);
                    559:        a = decode_attrib(&msg);
                    560:
                    561:        debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
                    562:
                    563:        xfree(longname);
                    564:
                    565:        buffer_free(&msg);
                    566:
                    567:        return(filename);
                    568: }
                    569:
                    570: int
                    571: do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
                    572: {
                    573:        Buffer msg;
                    574:        u_int status, id;
                    575:
                    576:        buffer_init(&msg);
                    577:
                    578:        /* Send rename request */
1.4       djm       579:        id = msg_id++;
1.1       djm       580:        buffer_put_char(&msg, SSH2_FXP_RENAME);
                    581:        buffer_put_int(&msg, id);
                    582:        buffer_put_cstring(&msg, oldpath);
                    583:        buffer_put_cstring(&msg, newpath);
                    584:        send_msg(fd_out, &msg);
                    585:        debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
                    586:            newpath);
                    587:        buffer_free(&msg);
                    588:
                    589:        status = get_status(fd_in, id);
                    590:        if (status != SSH2_FX_OK)
                    591:                error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
                    592:                    fx2txt(status));
                    593:
                    594:        return(status);
1.11      djm       595: }
                    596:
                    597: int
                    598: do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
                    599: {
                    600:        Buffer msg;
                    601:        u_int status, id;
                    602:
                    603:        buffer_init(&msg);
                    604:
                    605:        /* Send rename request */
                    606:        id = msg_id++;
                    607:        buffer_put_char(&msg, SSH2_FXP_SYMLINK);
                    608:        buffer_put_int(&msg, id);
                    609:        buffer_put_cstring(&msg, oldpath);
                    610:        buffer_put_cstring(&msg, newpath);
                    611:        send_msg(fd_out, &msg);
                    612:        debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
                    613:            newpath);
                    614:        buffer_free(&msg);
                    615:
                    616:        status = get_status(fd_in, id);
                    617:        if (status != SSH2_FX_OK)
                    618:                error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
                    619:                    fx2txt(status));
                    620:
                    621:        return(status);
                    622: }
                    623:
                    624: char *
                    625: do_readlink(int fd_in, int fd_out, char *path)
                    626: {
                    627:        Buffer msg;
                    628:        u_int type, expected_id, count, id;
                    629:        char *filename, *longname;
                    630:        Attrib *a;
                    631:
                    632:        expected_id = id = msg_id++;
                    633:        send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
                    634:
                    635:        buffer_init(&msg);
                    636:
                    637:        get_msg(fd_in, &msg);
                    638:        type = buffer_get_char(&msg);
                    639:        id = buffer_get_int(&msg);
                    640:
                    641:        if (id != expected_id)
                    642:                fatal("ID mismatch (%d != %d)", id, expected_id);
                    643:
                    644:        if (type == SSH2_FXP_STATUS) {
                    645:                u_int status = buffer_get_int(&msg);
                    646:
                    647:                error("Couldn't readlink: %s", fx2txt(status));
                    648:                return(NULL);
                    649:        } else if (type != SSH2_FXP_NAME)
                    650:                fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
                    651:                    SSH2_FXP_NAME, type);
                    652:
                    653:        count = buffer_get_int(&msg);
                    654:        if (count != 1)
                    655:                fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
                    656:
                    657:        filename = buffer_get_string(&msg, NULL);
                    658:        longname = buffer_get_string(&msg, NULL);
                    659:        a = decode_attrib(&msg);
                    660:
                    661:        debug3("SSH_FXP_READLINK %s -> %s", path, filename);
                    662:
                    663:        xfree(longname);
                    664:
                    665:        buffer_free(&msg);
                    666:
                    667:        return(filename);
1.1       djm       668: }
                    669:
                    670: int
                    671: do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
                    672:     int pflag)
                    673: {
                    674:        int local_fd;
                    675:        u_int expected_id, handle_len, mode, type, id;
                    676:        u_int64_t offset;
                    677:        char *handle;
                    678:        Buffer msg;
                    679:        Attrib junk, *a;
1.5       djm       680:        int status;
1.1       djm       681:
1.14    ! djm       682:        a = do_stat(fd_in, fd_out, remote_path, 0);
1.1       djm       683:        if (a == NULL)
                    684:                return(-1);
                    685:
                    686:        /* XXX: should we preserve set[ug]id? */
                    687:        if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
                    688:                mode = S_IWRITE | (a->perm & 0777);
                    689:        else
                    690:                mode = 0666;
                    691:
1.14    ! djm       692:        if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
        !           693:            (a->perm & S_IFDIR)) {
        !           694:                error("Cannot download a directory: %s", remote_path);
        !           695:                return(-1);
        !           696:        }
        !           697:
1.1       djm       698:        local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
                    699:        if (local_fd == -1) {
                    700:                error("Couldn't open local file \"%s\" for writing: %s",
                    701:                    local_path, strerror(errno));
1.14    ! djm       702:                return(-1);
1.1       djm       703:        }
                    704:
                    705:        buffer_init(&msg);
                    706:
                    707:        /* Send open request */
1.4       djm       708:        id = msg_id++;
1.1       djm       709:        buffer_put_char(&msg, SSH2_FXP_OPEN);
                    710:        buffer_put_int(&msg, id);
                    711:        buffer_put_cstring(&msg, remote_path);
                    712:        buffer_put_int(&msg, SSH2_FXF_READ);
                    713:        attrib_clear(&junk); /* Send empty attributes */
                    714:        encode_attrib(&msg, &junk);
                    715:        send_msg(fd_out, &msg);
                    716:        debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
                    717:
                    718:        handle = get_handle(fd_in, id, &handle_len);
                    719:        if (handle == NULL) {
                    720:                buffer_free(&msg);
                    721:                close(local_fd);
                    722:                return(-1);
                    723:        }
                    724:
                    725:        /* Read from remote and write to local */
                    726:        offset = 0;
                    727:        for(;;) {
                    728:                u_int len;
                    729:                char *data;
                    730:
1.4       djm       731:                id = expected_id = msg_id++;
1.1       djm       732:
                    733:                buffer_clear(&msg);
                    734:                buffer_put_char(&msg, SSH2_FXP_READ);
                    735:                buffer_put_int(&msg, id);
                    736:                buffer_put_string(&msg, handle, handle_len);
                    737:                buffer_put_int64(&msg, offset);
                    738:                buffer_put_int(&msg, COPY_SIZE);
                    739:                send_msg(fd_out, &msg);
                    740:                debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
1.2       deraadt   741:                    id, (unsigned long long)offset, COPY_SIZE);
1.1       djm       742:
                    743:                buffer_clear(&msg);
                    744:
                    745:                get_msg(fd_in, &msg);
                    746:                type = buffer_get_char(&msg);
                    747:                id = buffer_get_int(&msg);
                    748:                debug3("Received reply T:%d I:%d", type, id);
                    749:                if (id != expected_id)
                    750:                        fatal("ID mismatch (%d != %d)", id, expected_id);
                    751:                if (type == SSH2_FXP_STATUS) {
1.5       djm       752:                        status = buffer_get_int(&msg);
1.1       djm       753:
                    754:                        if (status == SSH2_FX_EOF)
                    755:                                break;
                    756:                        else {
                    757:                                error("Couldn't read from remote "
                    758:                                    "file \"%s\" : %s", remote_path,
                    759:                                     fx2txt(status));
                    760:                                do_close(fd_in, fd_out, handle, handle_len);
1.5       djm       761:                                goto done;
1.1       djm       762:                        }
                    763:                } else if (type != SSH2_FXP_DATA) {
                    764:                        fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
                    765:                            SSH2_FXP_DATA, type);
                    766:                }
                    767:
                    768:                data = buffer_get_string(&msg, &len);
                    769:                if (len > COPY_SIZE)
                    770:                        fatal("Received more data than asked for %d > %d",
                    771:                            len, COPY_SIZE);
                    772:
1.6       itojun    773:                debug3("In read loop, got %d offset %llu", len,
1.2       deraadt   774:                    (unsigned long long)offset);
1.1       djm       775:                if (atomicio(write, local_fd, data, len) != len) {
                    776:                        error("Couldn't write to \"%s\": %s", local_path,
                    777:                            strerror(errno));
                    778:                        do_close(fd_in, fd_out, handle, handle_len);
1.5       djm       779:                        status = -1;
1.1       djm       780:                        xfree(data);
1.5       djm       781:                        goto done;
1.1       djm       782:                }
                    783:
                    784:                offset += len;
                    785:                xfree(data);
                    786:        }
1.5       djm       787:        status = do_close(fd_in, fd_out, handle, handle_len);
                    788:
1.10      djm       789:        /* Override umask and utimes if asked */
                    790:        if (pflag && fchmod(local_fd, mode) == -1)
                    791:                error("Couldn't set mode on \"%s\": %s", local_path,
                    792:                    strerror(errno));
                    793:        if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
                    794:                struct timeval tv[2];
                    795:                tv[0].tv_sec = a->atime;
                    796:                tv[1].tv_sec = a->mtime;
                    797:                tv[0].tv_usec = tv[1].tv_usec = 0;
                    798:                if (utimes(local_path, tv) == -1)
                    799:                        error("Can't set times on \"%s\": %s", local_path,
                    800:                            strerror(errno));
                    801:        }
                    802:
1.5       djm       803: done:
                    804:        close(local_fd);
                    805:        buffer_free(&msg);
1.1       djm       806:        xfree(handle);
1.5       djm       807:        return status;
1.1       djm       808: }
                    809:
                    810: int
                    811: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
                    812:     int pflag)
                    813: {
                    814:        int local_fd;
                    815:        u_int handle_len, id;
                    816:        u_int64_t offset;
                    817:        char *handle;
                    818:        Buffer msg;
                    819:        struct stat sb;
                    820:        Attrib a;
1.5       djm       821:        int status;
1.1       djm       822:
                    823:        if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
                    824:                error("Couldn't open local file \"%s\" for reading: %s",
                    825:                    local_path, strerror(errno));
                    826:                return(-1);
                    827:        }
                    828:        if (fstat(local_fd, &sb) == -1) {
                    829:                error("Couldn't fstat local file \"%s\": %s",
                    830:                    local_path, strerror(errno));
                    831:                close(local_fd);
                    832:                return(-1);
                    833:        }
                    834:        stat_to_attrib(&sb, &a);
                    835:
                    836:        a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
                    837:        a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
                    838:        a.perm &= 0777;
                    839:        if (!pflag)
                    840:                a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
                    841:
                    842:        buffer_init(&msg);
                    843:
                    844:        /* Send open request */
1.4       djm       845:        id = msg_id++;
1.1       djm       846:        buffer_put_char(&msg, SSH2_FXP_OPEN);
                    847:        buffer_put_int(&msg, id);
                    848:        buffer_put_cstring(&msg, remote_path);
                    849:        buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
                    850:        encode_attrib(&msg, &a);
                    851:        send_msg(fd_out, &msg);
                    852:        debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
                    853:
                    854:        buffer_clear(&msg);
                    855:
                    856:        handle = get_handle(fd_in, id, &handle_len);
                    857:        if (handle == NULL) {
                    858:                close(local_fd);
                    859:                buffer_free(&msg);
                    860:                return(-1);
                    861:        }
                    862:
                    863:        /* Read from local and write to remote */
                    864:        offset = 0;
                    865:        for(;;) {
                    866:                int len;
                    867:                char data[COPY_SIZE];
                    868:
                    869:                /*
                    870:                 * Can't use atomicio here because it returns 0 on EOF, thus losing
                    871:                 * the last block of the file
                    872:                 */
                    873:                do
                    874:                        len = read(local_fd, data, COPY_SIZE);
                    875:                while ((len == -1) && (errno == EINTR || errno == EAGAIN));
                    876:
                    877:                if (len == -1)
                    878:                        fatal("Couldn't read from \"%s\": %s", local_path,
                    879:                            strerror(errno));
                    880:                if (len == 0)
                    881:                        break;
                    882:
                    883:                buffer_clear(&msg);
                    884:                buffer_put_char(&msg, SSH2_FXP_WRITE);
                    885:                buffer_put_int(&msg, ++id);
                    886:                buffer_put_string(&msg, handle, handle_len);
                    887:                buffer_put_int64(&msg, offset);
                    888:                buffer_put_string(&msg, data, len);
                    889:                send_msg(fd_out, &msg);
                    890:                debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2       deraadt   891:                    id, (unsigned long long)offset, len);
1.1       djm       892:
                    893:                status = get_status(fd_in, id);
                    894:                if (status != SSH2_FX_OK) {
                    895:                        error("Couldn't write to remote file \"%s\": %s",
                    896:                            remote_path, fx2txt(status));
                    897:                        do_close(fd_in, fd_out, handle, handle_len);
                    898:                        close(local_fd);
1.5       djm       899:                        goto done;
1.1       djm       900:                }
1.2       deraadt   901:                debug3("In write loop, got %d offset %llu", len,
                    902:                    (unsigned long long)offset);
1.1       djm       903:
                    904:                offset += len;
                    905:        }
                    906:
                    907:        if (close(local_fd) == -1) {
                    908:                error("Couldn't close local file \"%s\": %s", local_path,
                    909:                    strerror(errno));
                    910:                do_close(fd_in, fd_out, handle, handle_len);
1.5       djm       911:                status = -1;
                    912:                goto done;
1.1       djm       913:        }
                    914:
1.10      djm       915:        /* Override umask and utimes if asked */
                    916:        if (pflag)
                    917:                do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
                    918:
1.5       djm       919:        status = do_close(fd_in, fd_out, handle, handle_len);
                    920:
                    921: done:
                    922:        xfree(handle);
                    923:        buffer_free(&msg);
                    924:        return status;
1.1       djm       925: }
1.12      djm       926: