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

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