1 /* $OpenBSD: sftp-client.c,v 1.155 2021/09/03 05:12:25 dtucker Exp $ */ 2 /* 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* XXX: memleaks */ 19 /* XXX: signed vs unsigned */ 20 /* XXX: remove all logging, only return status codes */ 21 /* XXX: copy between two remote sites */ 22 23 #include "includes.h" 24 25 #include <sys/types.h> 26 #ifdef HAVE_SYS_STATVFS_H 27 #include <sys/statvfs.h> 28 #endif 29 #include "openbsd-compat/sys-queue.h" 30 #ifdef HAVE_SYS_STAT_H 31 # include <sys/stat.h> 32 #endif 33 #ifdef HAVE_SYS_TIME_H 34 # include <sys/time.h> 35 #endif 36 #include <sys/uio.h> 37 38 #include <dirent.h> 39 #include <errno.h> 40 #ifdef HAVE_POLL_H 41 #include <poll.h> 42 #else 43 # ifdef HAVE_SYS_POLL_H 44 # include <sys/poll.h> 45 # endif 46 #endif 47 #include <fcntl.h> 48 #include <signal.h> 49 #include <stdarg.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include "xmalloc.h" 56 #include "ssherr.h" 57 #include "sshbuf.h" 58 #include "log.h" 59 #include "atomicio.h" 60 #include "progressmeter.h" 61 #include "misc.h" 62 #include "utf8.h" 63 64 #include "sftp.h" 65 #include "sftp-common.h" 66 #include "sftp-client.h" 67 68 extern volatile sig_atomic_t interrupted; 69 extern int showprogress; 70 71 /* Default size of buffer for up/download */ 72 #define DEFAULT_COPY_BUFLEN 32768 73 74 /* Default number of concurrent outstanding requests */ 75 #define DEFAULT_NUM_REQUESTS 64 76 77 /* Minimum amount of data to read at a time */ 78 #define MIN_READ_SIZE 512 79 80 /* Maximum depth to descend in directory trees */ 81 #define MAX_DIR_DEPTH 64 82 83 /* Directory separator characters */ 84 #ifdef HAVE_CYGWIN 85 # define SFTP_DIRECTORY_CHARS "/\\" 86 #else /* HAVE_CYGWIN */ 87 # define SFTP_DIRECTORY_CHARS "/" 88 #endif /* HAVE_CYGWIN */ 89 90 struct sftp_conn { 91 int fd_in; 92 int fd_out; 93 u_int download_buflen; 94 u_int upload_buflen; 95 u_int num_requests; 96 u_int version; 97 u_int msg_id; 98 #define SFTP_EXT_POSIX_RENAME 0x00000001 99 #define SFTP_EXT_STATVFS 0x00000002 100 #define SFTP_EXT_FSTATVFS 0x00000004 101 #define SFTP_EXT_HARDLINK 0x00000008 102 #define SFTP_EXT_FSYNC 0x00000010 103 #define SFTP_EXT_LSETSTAT 0x00000020 104 #define SFTP_EXT_LIMITS 0x00000040 105 #define SFTP_EXT_PATH_EXPAND 0x00000080 106 u_int exts; 107 u_int64_t limit_kbps; 108 struct bwlimit bwlimit_in, bwlimit_out; 109 }; 110 111 /* Tracks in-progress requests during file transfers */ 112 struct request { 113 u_int id; 114 size_t len; 115 u_int64_t offset; 116 TAILQ_ENTRY(request) tq; 117 }; 118 TAILQ_HEAD(requests, request); 119 120 static u_char * 121 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 122 const char *errfmt, ...) __attribute__((format(printf, 4, 5))); 123 124 static struct request * 125 request_enqueue(struct requests *requests, u_int id, size_t len, 126 uint64_t offset) 127 { 128 struct request *req; 129 130 req = xcalloc(1, sizeof(*req)); 131 req->id = id; 132 req->len = len; 133 req->offset = offset; 134 TAILQ_INSERT_TAIL(requests, req, tq); 135 return req; 136 } 137 138 static struct request * 139 request_find(struct requests *requests, u_int id) 140 { 141 struct request *req; 142 143 for (req = TAILQ_FIRST(requests); 144 req != NULL && req->id != id; 145 req = TAILQ_NEXT(req, tq)) 146 ; 147 return req; 148 } 149 150 /* ARGSUSED */ 151 static int 152 sftpio(void *_bwlimit, size_t amount) 153 { 154 struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 155 156 refresh_progress_meter(0); 157 if (bwlimit != NULL) 158 bandwidth_limit(bwlimit, amount); 159 return 0; 160 } 161 162 static void 163 send_msg(struct sftp_conn *conn, struct sshbuf *m) 164 { 165 u_char mlen[4]; 166 struct iovec iov[2]; 167 168 if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH) 169 fatal("Outbound message too long %zu", sshbuf_len(m)); 170 171 /* Send length first */ 172 put_u32(mlen, sshbuf_len(m)); 173 iov[0].iov_base = mlen; 174 iov[0].iov_len = sizeof(mlen); 175 iov[1].iov_base = (u_char *)sshbuf_ptr(m); 176 iov[1].iov_len = sshbuf_len(m); 177 178 if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio, 179 conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) != 180 sshbuf_len(m) + sizeof(mlen)) 181 fatal("Couldn't send packet: %s", strerror(errno)); 182 183 sshbuf_reset(m); 184 } 185 186 static void 187 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial) 188 { 189 u_int msg_len; 190 u_char *p; 191 int r; 192 193 sshbuf_reset(m); 194 if ((r = sshbuf_reserve(m, 4, &p)) != 0) 195 fatal_fr(r, "reserve"); 196 if (atomicio6(read, conn->fd_in, p, 4, sftpio, 197 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) { 198 if (errno == EPIPE || errno == ECONNRESET) 199 fatal("Connection closed"); 200 else 201 fatal("Couldn't read packet: %s", strerror(errno)); 202 } 203 204 if ((r = sshbuf_get_u32(m, &msg_len)) != 0) 205 fatal_fr(r, "sshbuf_get_u32"); 206 if (msg_len > SFTP_MAX_MSG_LENGTH) { 207 do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL, 208 "Received message too long %u", msg_len); 209 fatal("Ensure the remote shell produces no output " 210 "for non-interactive sessions."); 211 } 212 213 if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) 214 fatal_fr(r, "reserve"); 215 if (atomicio6(read, conn->fd_in, p, msg_len, sftpio, 216 conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) 217 != msg_len) { 218 if (errno == EPIPE) 219 fatal("Connection closed"); 220 else 221 fatal("Read packet: %s", strerror(errno)); 222 } 223 } 224 225 static void 226 get_msg(struct sftp_conn *conn, struct sshbuf *m) 227 { 228 get_msg_extended(conn, m, 0); 229 } 230 231 static void 232 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s, 233 u_int len) 234 { 235 struct sshbuf *msg; 236 int r; 237 238 if ((msg = sshbuf_new()) == NULL) 239 fatal_f("sshbuf_new failed"); 240 if ((r = sshbuf_put_u8(msg, code)) != 0 || 241 (r = sshbuf_put_u32(msg, id)) != 0 || 242 (r = sshbuf_put_string(msg, s, len)) != 0) 243 fatal_fr(r, "compose"); 244 send_msg(conn, msg); 245 debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 246 sshbuf_free(msg); 247 } 248 249 static void 250 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, 251 const void *s, u_int len, Attrib *a) 252 { 253 struct sshbuf *msg; 254 int r; 255 256 if ((msg = sshbuf_new()) == NULL) 257 fatal_f("sshbuf_new failed"); 258 if ((r = sshbuf_put_u8(msg, code)) != 0 || 259 (r = sshbuf_put_u32(msg, id)) != 0 || 260 (r = sshbuf_put_string(msg, s, len)) != 0 || 261 (r = encode_attrib(msg, a)) != 0) 262 fatal_fr(r, "compose"); 263 send_msg(conn, msg); 264 debug3("Sent message fd %d T:%u I:%u F:0x%04x M:%05o", 265 conn->fd_out, code, id, a->flags, a->perm); 266 sshbuf_free(msg); 267 } 268 269 static u_int 270 get_status(struct sftp_conn *conn, u_int expected_id) 271 { 272 struct sshbuf *msg; 273 u_char type; 274 u_int id, status; 275 int r; 276 277 if ((msg = sshbuf_new()) == NULL) 278 fatal_f("sshbuf_new failed"); 279 get_msg(conn, msg); 280 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 281 (r = sshbuf_get_u32(msg, &id)) != 0) 282 fatal_fr(r, "compose"); 283 284 if (id != expected_id) 285 fatal("ID mismatch (%u != %u)", id, expected_id); 286 if (type != SSH2_FXP_STATUS) 287 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 288 SSH2_FXP_STATUS, type); 289 290 if ((r = sshbuf_get_u32(msg, &status)) != 0) 291 fatal_fr(r, "parse"); 292 sshbuf_free(msg); 293 294 debug3("SSH2_FXP_STATUS %u", status); 295 296 return status; 297 } 298 299 static u_char * 300 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, 301 const char *errfmt, ...) 302 { 303 struct sshbuf *msg; 304 u_int id, status; 305 u_char type; 306 u_char *handle; 307 char errmsg[256]; 308 va_list args; 309 int r; 310 311 va_start(args, errfmt); 312 if (errfmt != NULL) 313 vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 314 va_end(args); 315 316 if ((msg = sshbuf_new()) == NULL) 317 fatal_f("sshbuf_new failed"); 318 get_msg(conn, msg); 319 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 320 (r = sshbuf_get_u32(msg, &id)) != 0) 321 fatal_fr(r, "parse"); 322 323 if (id != expected_id) 324 fatal("%s: ID mismatch (%u != %u)", 325 errfmt == NULL ? __func__ : errmsg, id, expected_id); 326 if (type == SSH2_FXP_STATUS) { 327 if ((r = sshbuf_get_u32(msg, &status)) != 0) 328 fatal_fr(r, "parse status"); 329 if (errfmt != NULL) 330 error("%s: %s", errmsg, fx2txt(status)); 331 sshbuf_free(msg); 332 return(NULL); 333 } else if (type != SSH2_FXP_HANDLE) 334 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 335 errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 336 337 if ((r = sshbuf_get_string(msg, &handle, len)) != 0) 338 fatal_fr(r, "parse handle"); 339 sshbuf_free(msg); 340 341 return handle; 342 } 343 344 /* XXX returing &static is error-prone. Refactor to fill *Attrib argument */ 345 static Attrib * 346 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) 347 { 348 struct sshbuf *msg; 349 u_int id; 350 u_char type; 351 int r; 352 static Attrib a; 353 354 if ((msg = sshbuf_new()) == NULL) 355 fatal_f("sshbuf_new failed"); 356 get_msg(conn, msg); 357 358 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 359 (r = sshbuf_get_u32(msg, &id)) != 0) 360 fatal_fr(r, "parse"); 361 362 if (id != expected_id) 363 fatal("ID mismatch (%u != %u)", id, expected_id); 364 if (type == SSH2_FXP_STATUS) { 365 u_int status; 366 367 if ((r = sshbuf_get_u32(msg, &status)) != 0) 368 fatal_fr(r, "parse status"); 369 if (quiet) 370 debug("Couldn't stat remote file: %s", fx2txt(status)); 371 else 372 error("Couldn't stat remote file: %s", fx2txt(status)); 373 sshbuf_free(msg); 374 return(NULL); 375 } else if (type != SSH2_FXP_ATTRS) { 376 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 377 SSH2_FXP_ATTRS, type); 378 } 379 if ((r = decode_attrib(msg, &a)) != 0) { 380 error_fr(r, "decode_attrib"); 381 sshbuf_free(msg); 382 return NULL; 383 } 384 debug3("Recevied stat reply T:%u I:%u F:0x%04x M:%05o", 385 type, id, a.flags, a.perm); 386 sshbuf_free(msg); 387 388 return &a; 389 } 390 391 static int 392 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, 393 u_int expected_id, int quiet) 394 { 395 struct sshbuf *msg; 396 u_char type; 397 u_int id; 398 u_int64_t flag; 399 int r; 400 401 if ((msg = sshbuf_new()) == NULL) 402 fatal_f("sshbuf_new failed"); 403 get_msg(conn, msg); 404 405 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 406 (r = sshbuf_get_u32(msg, &id)) != 0) 407 fatal_fr(r, "parse"); 408 409 debug3("Received statvfs reply T:%u I:%u", type, id); 410 if (id != expected_id) 411 fatal("ID mismatch (%u != %u)", id, expected_id); 412 if (type == SSH2_FXP_STATUS) { 413 u_int status; 414 415 if ((r = sshbuf_get_u32(msg, &status)) != 0) 416 fatal_fr(r, "parse status"); 417 if (quiet) 418 debug("Couldn't statvfs: %s", fx2txt(status)); 419 else 420 error("Couldn't statvfs: %s", fx2txt(status)); 421 sshbuf_free(msg); 422 return -1; 423 } else if (type != SSH2_FXP_EXTENDED_REPLY) { 424 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 425 SSH2_FXP_EXTENDED_REPLY, type); 426 } 427 428 memset(st, 0, sizeof(*st)); 429 if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 || 430 (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 || 431 (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 || 432 (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 || 433 (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 || 434 (r = sshbuf_get_u64(msg, &st->f_files)) != 0 || 435 (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 || 436 (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 || 437 (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 || 438 (r = sshbuf_get_u64(msg, &flag)) != 0 || 439 (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0) 440 fatal_fr(r, "parse statvfs"); 441 442 st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 443 st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 444 445 sshbuf_free(msg); 446 447 return 0; 448 } 449 450 struct sftp_conn * 451 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, 452 u_int64_t limit_kbps) 453 { 454 u_char type; 455 struct sshbuf *msg; 456 struct sftp_conn *ret; 457 int r; 458 459 ret = xcalloc(1, sizeof(*ret)); 460 ret->msg_id = 1; 461 ret->fd_in = fd_in; 462 ret->fd_out = fd_out; 463 ret->download_buflen = ret->upload_buflen = 464 transfer_buflen ? transfer_buflen : DEFAULT_COPY_BUFLEN; 465 ret->num_requests = 466 num_requests ? num_requests : DEFAULT_NUM_REQUESTS; 467 ret->exts = 0; 468 ret->limit_kbps = 0; 469 470 if ((msg = sshbuf_new()) == NULL) 471 fatal_f("sshbuf_new failed"); 472 if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 || 473 (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0) 474 fatal_fr(r, "parse"); 475 476 send_msg(ret, msg); 477 478 get_msg_extended(ret, msg, 1); 479 480 /* Expecting a VERSION reply */ 481 if ((r = sshbuf_get_u8(msg, &type)) != 0) 482 fatal_fr(r, "parse type"); 483 if (type != SSH2_FXP_VERSION) { 484 error("Invalid packet back from SSH2_FXP_INIT (type %u)", 485 type); 486 sshbuf_free(msg); 487 free(ret); 488 return(NULL); 489 } 490 if ((r = sshbuf_get_u32(msg, &ret->version)) != 0) 491 fatal_fr(r, "parse version"); 492 493 debug2("Remote version: %u", ret->version); 494 495 /* Check for extensions */ 496 while (sshbuf_len(msg) > 0) { 497 char *name; 498 u_char *value; 499 size_t vlen; 500 int known = 0; 501 502 if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 || 503 (r = sshbuf_get_string(msg, &value, &vlen)) != 0) 504 fatal_fr(r, "parse extension"); 505 if (strcmp(name, "posix-rename@openssh.com") == 0 && 506 strcmp((char *)value, "1") == 0) { 507 ret->exts |= SFTP_EXT_POSIX_RENAME; 508 known = 1; 509 } else if (strcmp(name, "statvfs@openssh.com") == 0 && 510 strcmp((char *)value, "2") == 0) { 511 ret->exts |= SFTP_EXT_STATVFS; 512 known = 1; 513 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && 514 strcmp((char *)value, "2") == 0) { 515 ret->exts |= SFTP_EXT_FSTATVFS; 516 known = 1; 517 } else if (strcmp(name, "hardlink@openssh.com") == 0 && 518 strcmp((char *)value, "1") == 0) { 519 ret->exts |= SFTP_EXT_HARDLINK; 520 known = 1; 521 } else if (strcmp(name, "fsync@openssh.com") == 0 && 522 strcmp((char *)value, "1") == 0) { 523 ret->exts |= SFTP_EXT_FSYNC; 524 known = 1; 525 } else if (strcmp(name, "lsetstat@openssh.com") == 0 && 526 strcmp((char *)value, "1") == 0) { 527 ret->exts |= SFTP_EXT_LSETSTAT; 528 known = 1; 529 } else if (strcmp(name, "limits@openssh.com") == 0 && 530 strcmp((char *)value, "1") == 0) { 531 ret->exts |= SFTP_EXT_LIMITS; 532 known = 1; 533 } else if (strcmp(name, "expand-path@openssh.com") == 0 && 534 strcmp((char *)value, "1") == 0) { 535 ret->exts |= SFTP_EXT_PATH_EXPAND; 536 known = 1; 537 } 538 if (known) { 539 debug2("Server supports extension \"%s\" revision %s", 540 name, value); 541 } else { 542 debug2("Unrecognised server extension \"%s\"", name); 543 } 544 free(name); 545 free(value); 546 } 547 548 sshbuf_free(msg); 549 550 /* Query the server for its limits */ 551 if (ret->exts & SFTP_EXT_LIMITS) { 552 struct sftp_limits limits; 553 if (do_limits(ret, &limits) != 0) 554 fatal_f("limits failed"); 555 556 /* If the caller did not specify, find a good value */ 557 if (transfer_buflen == 0) { 558 ret->download_buflen = limits.read_length; 559 ret->upload_buflen = limits.write_length; 560 debug("Using server download size %u", ret->download_buflen); 561 debug("Using server upload size %u", ret->upload_buflen); 562 } 563 564 /* Use the server limit to scale down our value only */ 565 if (num_requests == 0 && limits.open_handles) { 566 ret->num_requests = 567 MINIMUM(DEFAULT_NUM_REQUESTS, limits.open_handles); 568 debug("Server handle limit %llu; using %u", 569 (unsigned long long)limits.open_handles, 570 ret->num_requests); 571 } 572 } 573 574 /* Some filexfer v.0 servers don't support large packets */ 575 if (ret->version == 0) { 576 ret->download_buflen = MINIMUM(ret->download_buflen, 20480); 577 ret->upload_buflen = MINIMUM(ret->upload_buflen, 20480); 578 } 579 580 ret->limit_kbps = limit_kbps; 581 if (ret->limit_kbps > 0) { 582 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, 583 ret->download_buflen); 584 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, 585 ret->upload_buflen); 586 } 587 588 return ret; 589 } 590 591 u_int 592 sftp_proto_version(struct sftp_conn *conn) 593 { 594 return conn->version; 595 } 596 597 int 598 do_limits(struct sftp_conn *conn, struct sftp_limits *limits) 599 { 600 u_int id, msg_id; 601 u_char type; 602 struct sshbuf *msg; 603 int r; 604 605 if ((conn->exts & SFTP_EXT_LIMITS) == 0) { 606 error("Server does not support limits@openssh.com extension"); 607 return -1; 608 } 609 610 if ((msg = sshbuf_new()) == NULL) 611 fatal_f("sshbuf_new failed"); 612 613 id = conn->msg_id++; 614 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 615 (r = sshbuf_put_u32(msg, id)) != 0 || 616 (r = sshbuf_put_cstring(msg, "limits@openssh.com")) != 0) 617 fatal_fr(r, "compose"); 618 send_msg(conn, msg); 619 debug3("Sent message limits@openssh.com I:%u", id); 620 621 get_msg(conn, msg); 622 623 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 624 (r = sshbuf_get_u32(msg, &msg_id)) != 0) 625 fatal_fr(r, "parse"); 626 627 debug3("Received limits reply T:%u I:%u", type, msg_id); 628 if (id != msg_id) 629 fatal("ID mismatch (%u != %u)", msg_id, id); 630 if (type != SSH2_FXP_EXTENDED_REPLY) { 631 debug_f("expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 632 SSH2_FXP_EXTENDED_REPLY, type); 633 /* Disable the limits extension */ 634 conn->exts &= ~SFTP_EXT_LIMITS; 635 sshbuf_free(msg); 636 return 0; 637 } 638 639 memset(limits, 0, sizeof(*limits)); 640 if ((r = sshbuf_get_u64(msg, &limits->packet_length)) != 0 || 641 (r = sshbuf_get_u64(msg, &limits->read_length)) != 0 || 642 (r = sshbuf_get_u64(msg, &limits->write_length)) != 0 || 643 (r = sshbuf_get_u64(msg, &limits->open_handles)) != 0) 644 fatal_fr(r, "parse limits"); 645 646 sshbuf_free(msg); 647 648 return 0; 649 } 650 651 int 652 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) 653 { 654 u_int id, status; 655 struct sshbuf *msg; 656 int r; 657 658 if ((msg = sshbuf_new()) == NULL) 659 fatal_f("sshbuf_new failed"); 660 661 id = conn->msg_id++; 662 if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 || 663 (r = sshbuf_put_u32(msg, id)) != 0 || 664 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 665 fatal_fr(r, "parse"); 666 send_msg(conn, msg); 667 debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 668 669 status = get_status(conn, id); 670 if (status != SSH2_FX_OK) 671 error("Couldn't close file: %s", fx2txt(status)); 672 673 sshbuf_free(msg); 674 675 return status == SSH2_FX_OK ? 0 : -1; 676 } 677 678 679 static int 680 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, 681 SFTP_DIRENT ***dir) 682 { 683 struct sshbuf *msg; 684 u_int count, id, i, expected_id, ents = 0; 685 size_t handle_len; 686 u_char type, *handle; 687 int status = SSH2_FX_FAILURE; 688 int r; 689 690 if (dir) 691 *dir = NULL; 692 693 id = conn->msg_id++; 694 695 if ((msg = sshbuf_new()) == NULL) 696 fatal_f("sshbuf_new failed"); 697 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 || 698 (r = sshbuf_put_u32(msg, id)) != 0 || 699 (r = sshbuf_put_cstring(msg, path)) != 0) 700 fatal_fr(r, "compose OPENDIR"); 701 send_msg(conn, msg); 702 703 handle = get_handle(conn, id, &handle_len, 704 "remote readdir(\"%s\")", path); 705 if (handle == NULL) { 706 sshbuf_free(msg); 707 return -1; 708 } 709 710 if (dir) { 711 ents = 0; 712 *dir = xcalloc(1, sizeof(**dir)); 713 (*dir)[0] = NULL; 714 } 715 716 for (; !interrupted;) { 717 id = expected_id = conn->msg_id++; 718 719 debug3("Sending SSH2_FXP_READDIR I:%u", id); 720 721 sshbuf_reset(msg); 722 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 || 723 (r = sshbuf_put_u32(msg, id)) != 0 || 724 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 725 fatal_fr(r, "compose READDIR"); 726 send_msg(conn, msg); 727 728 sshbuf_reset(msg); 729 730 get_msg(conn, msg); 731 732 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 733 (r = sshbuf_get_u32(msg, &id)) != 0) 734 fatal_fr(r, "parse"); 735 736 debug3("Received reply T:%u I:%u", type, id); 737 738 if (id != expected_id) 739 fatal("ID mismatch (%u != %u)", id, expected_id); 740 741 if (type == SSH2_FXP_STATUS) { 742 u_int rstatus; 743 744 if ((r = sshbuf_get_u32(msg, &rstatus)) != 0) 745 fatal_fr(r, "parse status"); 746 debug3("Received SSH2_FXP_STATUS %d", rstatus); 747 if (rstatus == SSH2_FX_EOF) 748 break; 749 error("Couldn't read directory: %s", fx2txt(rstatus)); 750 goto out; 751 } else if (type != SSH2_FXP_NAME) 752 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 753 SSH2_FXP_NAME, type); 754 755 if ((r = sshbuf_get_u32(msg, &count)) != 0) 756 fatal_fr(r, "parse count"); 757 if (count > SSHBUF_SIZE_MAX) 758 fatal_f("nonsensical number of entries"); 759 if (count == 0) 760 break; 761 debug3("Received %d SSH2_FXP_NAME responses", count); 762 for (i = 0; i < count; i++) { 763 char *filename, *longname; 764 Attrib a; 765 766 if ((r = sshbuf_get_cstring(msg, &filename, 767 NULL)) != 0 || 768 (r = sshbuf_get_cstring(msg, &longname, 769 NULL)) != 0) 770 fatal_fr(r, "parse filenames"); 771 if ((r = decode_attrib(msg, &a)) != 0) { 772 error_fr(r, "couldn't decode attrib"); 773 free(filename); 774 free(longname); 775 goto out; 776 } 777 778 if (print_flag) 779 mprintf("%s\n", longname); 780 781 /* 782 * Directory entries should never contain '/' 783 * These can be used to attack recursive ops 784 * (e.g. send '../../../../etc/passwd') 785 */ 786 if (strpbrk(filename, SFTP_DIRECTORY_CHARS) != NULL) { 787 error("Server sent suspect path \"%s\" " 788 "during readdir of \"%s\"", filename, path); 789 } else if (dir) { 790 *dir = xreallocarray(*dir, ents + 2, sizeof(**dir)); 791 (*dir)[ents] = xcalloc(1, sizeof(***dir)); 792 (*dir)[ents]->filename = xstrdup(filename); 793 (*dir)[ents]->longname = xstrdup(longname); 794 memcpy(&(*dir)[ents]->a, &a, sizeof(a)); 795 (*dir)[++ents] = NULL; 796 } 797 free(filename); 798 free(longname); 799 } 800 } 801 status = 0; 802 803 out: 804 sshbuf_free(msg); 805 do_close(conn, handle, handle_len); 806 free(handle); 807 808 if (status != 0 && dir != NULL) { 809 /* Don't return results on error */ 810 free_sftp_dirents(*dir); 811 *dir = NULL; 812 } else if (interrupted && dir != NULL && *dir != NULL) { 813 /* Don't return partial matches on interrupt */ 814 free_sftp_dirents(*dir); 815 *dir = xcalloc(1, sizeof(**dir)); 816 **dir = NULL; 817 } 818 819 return status == SSH2_FX_OK ? 0 : -1; 820 } 821 822 int 823 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) 824 { 825 return(do_lsreaddir(conn, path, 0, dir)); 826 } 827 828 void free_sftp_dirents(SFTP_DIRENT **s) 829 { 830 int i; 831 832 if (s == NULL) 833 return; 834 for (i = 0; s[i]; i++) { 835 free(s[i]->filename); 836 free(s[i]->longname); 837 free(s[i]); 838 } 839 free(s); 840 } 841 842 int 843 do_rm(struct sftp_conn *conn, const char *path) 844 { 845 u_int status, id; 846 847 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 848 849 id = conn->msg_id++; 850 send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 851 status = get_status(conn, id); 852 if (status != SSH2_FX_OK) 853 error("Couldn't delete file: %s", fx2txt(status)); 854 return status == SSH2_FX_OK ? 0 : -1; 855 } 856 857 int 858 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) 859 { 860 u_int status, id; 861 862 id = conn->msg_id++; 863 send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 864 strlen(path), a); 865 866 status = get_status(conn, id); 867 if (status != SSH2_FX_OK && print_flag) 868 error("Couldn't create directory: %s", fx2txt(status)); 869 870 return status == SSH2_FX_OK ? 0 : -1; 871 } 872 873 int 874 do_rmdir(struct sftp_conn *conn, const char *path) 875 { 876 u_int status, id; 877 878 id = conn->msg_id++; 879 send_string_request(conn, id, SSH2_FXP_RMDIR, path, 880 strlen(path)); 881 882 status = get_status(conn, id); 883 if (status != SSH2_FX_OK) 884 error("Couldn't remove directory: %s", fx2txt(status)); 885 886 return status == SSH2_FX_OK ? 0 : -1; 887 } 888 889 Attrib * 890 do_stat(struct sftp_conn *conn, const char *path, int quiet) 891 { 892 u_int id; 893 894 id = conn->msg_id++; 895 896 send_string_request(conn, id, 897 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 898 path, strlen(path)); 899 900 return(get_decode_stat(conn, id, quiet)); 901 } 902 903 Attrib * 904 do_lstat(struct sftp_conn *conn, const char *path, int quiet) 905 { 906 u_int id; 907 908 if (conn->version == 0) { 909 if (quiet) 910 debug("Server version does not support lstat operation"); 911 else 912 logit("Server version does not support lstat operation"); 913 return(do_stat(conn, path, quiet)); 914 } 915 916 id = conn->msg_id++; 917 send_string_request(conn, id, SSH2_FXP_LSTAT, path, 918 strlen(path)); 919 920 return(get_decode_stat(conn, id, quiet)); 921 } 922 923 #ifdef notyet 924 Attrib * 925 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 926 int quiet) 927 { 928 u_int id; 929 930 id = conn->msg_id++; 931 send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 932 handle_len); 933 934 return(get_decode_stat(conn, id, quiet)); 935 } 936 #endif 937 938 int 939 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) 940 { 941 u_int status, id; 942 943 id = conn->msg_id++; 944 send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 945 strlen(path), a); 946 947 status = get_status(conn, id); 948 if (status != SSH2_FX_OK) 949 error("Couldn't setstat on \"%s\": %s", path, 950 fx2txt(status)); 951 952 return status == SSH2_FX_OK ? 0 : -1; 953 } 954 955 int 956 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 957 Attrib *a) 958 { 959 u_int status, id; 960 961 id = conn->msg_id++; 962 send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 963 handle_len, a); 964 965 status = get_status(conn, id); 966 if (status != SSH2_FX_OK) 967 error("Couldn't fsetstat: %s", fx2txt(status)); 968 969 return status == SSH2_FX_OK ? 0 : -1; 970 } 971 972 /* Implements both the realpath and expand-path operations */ 973 static char * 974 do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) 975 { 976 struct sshbuf *msg; 977 u_int expected_id, count, id; 978 char *filename, *longname; 979 Attrib a; 980 u_char type; 981 int r; 982 const char *what = "SSH2_FXP_REALPATH"; 983 984 if (expand) 985 what = "expand-path@openssh.com"; 986 if ((msg = sshbuf_new()) == NULL) 987 fatal_f("sshbuf_new failed"); 988 989 expected_id = id = conn->msg_id++; 990 if (expand) { 991 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 992 (r = sshbuf_put_u32(msg, id)) != 0 || 993 (r = sshbuf_put_cstring(msg, 994 "expand-path@openssh.com")) != 0 || 995 (r = sshbuf_put_cstring(msg, path)) != 0) 996 fatal_fr(r, "compose %s", what); 997 send_msg(conn, msg); 998 } else { 999 send_string_request(conn, id, SSH2_FXP_REALPATH, 1000 path, strlen(path)); 1001 } 1002 get_msg(conn, msg); 1003 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1004 (r = sshbuf_get_u32(msg, &id)) != 0) 1005 fatal_fr(r, "parse"); 1006 1007 if (id != expected_id) 1008 fatal("ID mismatch (%u != %u)", id, expected_id); 1009 1010 if (type == SSH2_FXP_STATUS) { 1011 u_int status; 1012 1013 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1014 fatal_fr(r, "parse status"); 1015 error("Couldn't canonicalize: %s", fx2txt(status)); 1016 sshbuf_free(msg); 1017 return NULL; 1018 } else if (type != SSH2_FXP_NAME) 1019 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1020 SSH2_FXP_NAME, type); 1021 1022 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1023 fatal_fr(r, "parse count"); 1024 if (count != 1) 1025 fatal("Got multiple names (%d) from %s", count, what); 1026 1027 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1028 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1029 (r = decode_attrib(msg, &a)) != 0) 1030 fatal_fr(r, "parse filename/attrib"); 1031 1032 debug3("%s %s -> %s", what, path, filename); 1033 1034 free(longname); 1035 1036 sshbuf_free(msg); 1037 1038 return(filename); 1039 } 1040 1041 char * 1042 do_realpath(struct sftp_conn *conn, const char *path) 1043 { 1044 return do_realpath_expand(conn, path, 0); 1045 } 1046 1047 int 1048 can_expand_path(struct sftp_conn *conn) 1049 { 1050 return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0; 1051 } 1052 1053 char * 1054 do_expand_path(struct sftp_conn *conn, const char *path) 1055 { 1056 if (!can_expand_path(conn)) { 1057 debug3_f("no server support, fallback to realpath"); 1058 return do_realpath_expand(conn, path, 0); 1059 } 1060 return do_realpath_expand(conn, path, 1); 1061 } 1062 1063 int 1064 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, 1065 int force_legacy) 1066 { 1067 struct sshbuf *msg; 1068 u_int status, id; 1069 int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; 1070 1071 if ((msg = sshbuf_new()) == NULL) 1072 fatal_f("sshbuf_new failed"); 1073 1074 /* Send rename request */ 1075 id = conn->msg_id++; 1076 if (use_ext) { 1077 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1078 (r = sshbuf_put_u32(msg, id)) != 0 || 1079 (r = sshbuf_put_cstring(msg, 1080 "posix-rename@openssh.com")) != 0) 1081 fatal_fr(r, "compose posix-rename"); 1082 } else { 1083 if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 || 1084 (r = sshbuf_put_u32(msg, id)) != 0) 1085 fatal_fr(r, "compose rename"); 1086 } 1087 if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1088 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1089 fatal_fr(r, "compose paths"); 1090 send_msg(conn, msg); 1091 debug3("Sent message %s \"%s\" -> \"%s\"", 1092 use_ext ? "posix-rename@openssh.com" : 1093 "SSH2_FXP_RENAME", oldpath, newpath); 1094 sshbuf_free(msg); 1095 1096 status = get_status(conn, id); 1097 if (status != SSH2_FX_OK) 1098 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 1099 newpath, fx2txt(status)); 1100 1101 return status == SSH2_FX_OK ? 0 : -1; 1102 } 1103 1104 int 1105 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 1106 { 1107 struct sshbuf *msg; 1108 u_int status, id; 1109 int r; 1110 1111 if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 1112 error("Server does not support hardlink@openssh.com extension"); 1113 return -1; 1114 } 1115 1116 if ((msg = sshbuf_new()) == NULL) 1117 fatal_f("sshbuf_new failed"); 1118 1119 /* Send link request */ 1120 id = conn->msg_id++; 1121 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1122 (r = sshbuf_put_u32(msg, id)) != 0 || 1123 (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || 1124 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1125 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1126 fatal_fr(r, "compose"); 1127 send_msg(conn, msg); 1128 debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 1129 oldpath, newpath); 1130 sshbuf_free(msg); 1131 1132 status = get_status(conn, id); 1133 if (status != SSH2_FX_OK) 1134 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, 1135 newpath, fx2txt(status)); 1136 1137 return status == SSH2_FX_OK ? 0 : -1; 1138 } 1139 1140 int 1141 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) 1142 { 1143 struct sshbuf *msg; 1144 u_int status, id; 1145 int r; 1146 1147 if (conn->version < 3) { 1148 error("This server does not support the symlink operation"); 1149 return(SSH2_FX_OP_UNSUPPORTED); 1150 } 1151 1152 if ((msg = sshbuf_new()) == NULL) 1153 fatal_f("sshbuf_new failed"); 1154 1155 /* Send symlink request */ 1156 id = conn->msg_id++; 1157 if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 || 1158 (r = sshbuf_put_u32(msg, id)) != 0 || 1159 (r = sshbuf_put_cstring(msg, oldpath)) != 0 || 1160 (r = sshbuf_put_cstring(msg, newpath)) != 0) 1161 fatal_fr(r, "compose"); 1162 send_msg(conn, msg); 1163 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 1164 newpath); 1165 sshbuf_free(msg); 1166 1167 status = get_status(conn, id); 1168 if (status != SSH2_FX_OK) 1169 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 1170 newpath, fx2txt(status)); 1171 1172 return status == SSH2_FX_OK ? 0 : -1; 1173 } 1174 1175 int 1176 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) 1177 { 1178 struct sshbuf *msg; 1179 u_int status, id; 1180 int r; 1181 1182 /* Silently return if the extension is not supported */ 1183 if ((conn->exts & SFTP_EXT_FSYNC) == 0) 1184 return -1; 1185 1186 /* Send fsync request */ 1187 if ((msg = sshbuf_new()) == NULL) 1188 fatal_f("sshbuf_new failed"); 1189 id = conn->msg_id++; 1190 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1191 (r = sshbuf_put_u32(msg, id)) != 0 || 1192 (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || 1193 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1194 fatal_fr(r, "compose"); 1195 send_msg(conn, msg); 1196 debug3("Sent message fsync@openssh.com I:%u", id); 1197 sshbuf_free(msg); 1198 1199 status = get_status(conn, id); 1200 if (status != SSH2_FX_OK) 1201 error("Couldn't sync file: %s", fx2txt(status)); 1202 1203 return status == SSH2_FX_OK ? 0 : -1; 1204 } 1205 1206 #ifdef notyet 1207 char * 1208 do_readlink(struct sftp_conn *conn, const char *path) 1209 { 1210 struct sshbuf *msg; 1211 u_int expected_id, count, id; 1212 char *filename, *longname; 1213 Attrib a; 1214 u_char type; 1215 int r; 1216 1217 expected_id = id = conn->msg_id++; 1218 send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 1219 1220 if ((msg = sshbuf_new()) == NULL) 1221 fatal_f("sshbuf_new failed"); 1222 1223 get_msg(conn, msg); 1224 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1225 (r = sshbuf_get_u32(msg, &id)) != 0) 1226 fatal_fr(r, "parse"); 1227 1228 if (id != expected_id) 1229 fatal("ID mismatch (%u != %u)", id, expected_id); 1230 1231 if (type == SSH2_FXP_STATUS) { 1232 u_int status; 1233 1234 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1235 fatal_fr(r, "parse status"); 1236 error("Couldn't readlink: %s", fx2txt(status)); 1237 sshbuf_free(msg); 1238 return(NULL); 1239 } else if (type != SSH2_FXP_NAME) 1240 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 1241 SSH2_FXP_NAME, type); 1242 1243 if ((r = sshbuf_get_u32(msg, &count)) != 0) 1244 fatal_fr(r, "parse count"); 1245 if (count != 1) 1246 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 1247 1248 if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || 1249 (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || 1250 (r = decode_attrib(msg, &a)) != 0) 1251 fatal_fr(r, "parse filenames/attrib"); 1252 1253 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 1254 1255 free(longname); 1256 1257 sshbuf_free(msg); 1258 1259 return filename; 1260 } 1261 #endif 1262 1263 int 1264 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 1265 int quiet) 1266 { 1267 struct sshbuf *msg; 1268 u_int id; 1269 int r; 1270 1271 if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 1272 error("Server does not support statvfs@openssh.com extension"); 1273 return -1; 1274 } 1275 1276 id = conn->msg_id++; 1277 1278 if ((msg = sshbuf_new()) == NULL) 1279 fatal_f("sshbuf_new failed"); 1280 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1281 (r = sshbuf_put_u32(msg, id)) != 0 || 1282 (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || 1283 (r = sshbuf_put_cstring(msg, path)) != 0) 1284 fatal_fr(r, "compose"); 1285 send_msg(conn, msg); 1286 sshbuf_free(msg); 1287 1288 return get_decode_statvfs(conn, st, id, quiet); 1289 } 1290 1291 #ifdef notyet 1292 int 1293 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, 1294 struct sftp_statvfs *st, int quiet) 1295 { 1296 struct sshbuf *msg; 1297 u_int id; 1298 1299 if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 1300 error("Server does not support fstatvfs@openssh.com extension"); 1301 return -1; 1302 } 1303 1304 id = conn->msg_id++; 1305 1306 if ((msg = sshbuf_new()) == NULL) 1307 fatal_f("sshbuf_new failed"); 1308 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1309 (r = sshbuf_put_u32(msg, id)) != 0 || 1310 (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || 1311 (r = sshbuf_put_string(msg, handle, handle_len)) != 0) 1312 fatal_fr(r, "compose"); 1313 send_msg(conn, msg); 1314 sshbuf_free(msg); 1315 1316 return get_decode_statvfs(conn, st, id, quiet); 1317 } 1318 #endif 1319 1320 int 1321 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) 1322 { 1323 struct sshbuf *msg; 1324 u_int status, id; 1325 int r; 1326 1327 if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) { 1328 error("Server does not support lsetstat@openssh.com extension"); 1329 return -1; 1330 } 1331 1332 id = conn->msg_id++; 1333 if ((msg = sshbuf_new()) == NULL) 1334 fatal_f("sshbuf_new failed"); 1335 if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || 1336 (r = sshbuf_put_u32(msg, id)) != 0 || 1337 (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 || 1338 (r = sshbuf_put_cstring(msg, path)) != 0 || 1339 (r = encode_attrib(msg, a)) != 0) 1340 fatal_fr(r, "compose"); 1341 send_msg(conn, msg); 1342 sshbuf_free(msg); 1343 1344 status = get_status(conn, id); 1345 if (status != SSH2_FX_OK) 1346 error("Couldn't setstat on \"%s\": %s", path, 1347 fx2txt(status)); 1348 1349 return status == SSH2_FX_OK ? 0 : -1; 1350 } 1351 1352 static void 1353 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 1354 u_int len, const u_char *handle, u_int handle_len) 1355 { 1356 struct sshbuf *msg; 1357 int r; 1358 1359 if ((msg = sshbuf_new()) == NULL) 1360 fatal_f("sshbuf_new failed"); 1361 if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 || 1362 (r = sshbuf_put_u32(msg, id)) != 0 || 1363 (r = sshbuf_put_string(msg, handle, handle_len)) != 0 || 1364 (r = sshbuf_put_u64(msg, offset)) != 0 || 1365 (r = sshbuf_put_u32(msg, len)) != 0) 1366 fatal_fr(r, "compose"); 1367 send_msg(conn, msg); 1368 sshbuf_free(msg); 1369 } 1370 1371 static int 1372 send_open(struct sftp_conn *conn, const char *path, const char *tag, 1373 u_int openmode, Attrib *a, u_char **handlep, size_t *handle_lenp) 1374 { 1375 Attrib junk; 1376 u_char *handle; 1377 size_t handle_len; 1378 struct sshbuf *msg; 1379 int r; 1380 u_int id; 1381 1382 *handlep = NULL; 1383 *handle_lenp = 0; 1384 1385 if (a == NULL) { 1386 attrib_clear(&junk); /* Send empty attributes */ 1387 a = &junk; 1388 } 1389 /* Send open request */ 1390 if ((msg = sshbuf_new()) == NULL) 1391 fatal_f("sshbuf_new failed"); 1392 id = conn->msg_id++; 1393 if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || 1394 (r = sshbuf_put_u32(msg, id)) != 0 || 1395 (r = sshbuf_put_cstring(msg, path)) != 0 || 1396 (r = sshbuf_put_u32(msg, openmode)) != 0 || 1397 (r = encode_attrib(msg, a)) != 0) 1398 fatal_fr(r, "compose %s open", tag); 1399 send_msg(conn, msg); 1400 sshbuf_free(msg); 1401 debug3("Sent %s message SSH2_FXP_OPEN I:%u P:%s M:0x%04x", 1402 tag, id, path, openmode); 1403 if ((handle = get_handle(conn, id, &handle_len, 1404 "%s open(\"%s\")", tag, path)) == NULL) 1405 return -1; 1406 /* success */ 1407 *handlep = handle; 1408 *handle_lenp = handle_len; 1409 return 0; 1410 } 1411 1412 static const char * 1413 progress_meter_path(const char *path) 1414 { 1415 const char *progresspath; 1416 1417 if ((progresspath = strrchr(path, '/')) == NULL) 1418 return path; 1419 progresspath++; 1420 if (*progresspath == '\0') 1421 return path; 1422 return progresspath; 1423 } 1424 1425 int 1426 do_download(struct sftp_conn *conn, const char *remote_path, 1427 const char *local_path, Attrib *a, int preserve_flag, int resume_flag, 1428 int fsync_flag) 1429 { 1430 struct sshbuf *msg; 1431 u_char *handle; 1432 int local_fd = -1, write_error; 1433 int read_error, write_errno, lmodified = 0, reordered = 0, r; 1434 u_int64_t offset = 0, size, highwater; 1435 u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; 1436 off_t progress_counter; 1437 size_t handle_len; 1438 struct stat st; 1439 struct requests requests; 1440 struct request *req; 1441 u_char type; 1442 1443 TAILQ_INIT(&requests); 1444 1445 if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 1446 return -1; 1447 1448 /* Do not preserve set[ug]id here, as we do not preserve ownership */ 1449 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1450 mode = a->perm & 0777; 1451 else 1452 mode = 0666; 1453 1454 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 1455 (!S_ISREG(a->perm))) { 1456 error("Cannot download non-regular file: %s", remote_path); 1457 return(-1); 1458 } 1459 1460 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1461 size = a->size; 1462 else 1463 size = 0; 1464 1465 buflen = conn->download_buflen; 1466 1467 /* Send open request */ 1468 if (send_open(conn, remote_path, "remote", SSH2_FXF_READ, NULL, 1469 &handle, &handle_len) != 0) 1470 return -1; 1471 1472 local_fd = open(local_path, 1473 O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); 1474 if (local_fd == -1) { 1475 error("Couldn't open local file \"%s\" for writing: %s", 1476 local_path, strerror(errno)); 1477 goto fail; 1478 } 1479 offset = highwater = 0; 1480 if (resume_flag) { 1481 if (fstat(local_fd, &st) == -1) { 1482 error("Unable to stat local file \"%s\": %s", 1483 local_path, strerror(errno)); 1484 goto fail; 1485 } 1486 if (st.st_size < 0) { 1487 error("\"%s\" has negative size", local_path); 1488 goto fail; 1489 } 1490 if ((u_int64_t)st.st_size > size) { 1491 error("Unable to resume download of \"%s\": " 1492 "local file is larger than remote", local_path); 1493 fail: 1494 do_close(conn, handle, handle_len); 1495 free(handle); 1496 if (local_fd != -1) 1497 close(local_fd); 1498 return -1; 1499 } 1500 offset = highwater = st.st_size; 1501 } 1502 1503 /* Read from remote and write to local */ 1504 write_error = read_error = write_errno = num_req = 0; 1505 max_req = 1; 1506 progress_counter = offset; 1507 1508 if (showprogress && size != 0) { 1509 start_progress_meter(progress_meter_path(remote_path), 1510 size, &progress_counter); 1511 } 1512 1513 if ((msg = sshbuf_new()) == NULL) 1514 fatal_f("sshbuf_new failed"); 1515 1516 while (num_req > 0 || max_req > 0) { 1517 u_char *data; 1518 size_t len; 1519 1520 /* 1521 * Simulate EOF on interrupt: stop sending new requests and 1522 * allow outstanding requests to drain gracefully 1523 */ 1524 if (interrupted) { 1525 if (num_req == 0) /* If we haven't started yet... */ 1526 break; 1527 max_req = 0; 1528 } 1529 1530 /* Send some more requests */ 1531 while (num_req < max_req) { 1532 debug3("Request range %llu -> %llu (%d/%d)", 1533 (unsigned long long)offset, 1534 (unsigned long long)offset + buflen - 1, 1535 num_req, max_req); 1536 req = request_enqueue(&requests, conn->msg_id++, 1537 buflen, offset); 1538 offset += buflen; 1539 num_req++; 1540 send_read_request(conn, req->id, req->offset, 1541 req->len, handle, handle_len); 1542 } 1543 1544 sshbuf_reset(msg); 1545 get_msg(conn, msg); 1546 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1547 (r = sshbuf_get_u32(msg, &id)) != 0) 1548 fatal_fr(r, "parse"); 1549 debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 1550 1551 /* Find the request in our queue */ 1552 if ((req = request_find(&requests, id)) == NULL) 1553 fatal("Unexpected reply %u", id); 1554 1555 switch (type) { 1556 case SSH2_FXP_STATUS: 1557 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1558 fatal_fr(r, "parse status"); 1559 if (status != SSH2_FX_EOF) 1560 read_error = 1; 1561 max_req = 0; 1562 TAILQ_REMOVE(&requests, req, tq); 1563 free(req); 1564 num_req--; 1565 break; 1566 case SSH2_FXP_DATA: 1567 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 1568 fatal_fr(r, "parse data"); 1569 debug3("Received data %llu -> %llu", 1570 (unsigned long long)req->offset, 1571 (unsigned long long)req->offset + len - 1); 1572 if (len > req->len) 1573 fatal("Received more data than asked for " 1574 "%zu > %zu", len, req->len); 1575 lmodified = 1; 1576 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 1577 atomicio(vwrite, local_fd, data, len) != len) && 1578 !write_error) { 1579 write_errno = errno; 1580 write_error = 1; 1581 max_req = 0; 1582 } 1583 else if (!reordered && req->offset <= highwater) 1584 highwater = req->offset + len; 1585 else if (!reordered && req->offset > highwater) 1586 reordered = 1; 1587 progress_counter += len; 1588 free(data); 1589 1590 if (len == req->len) { 1591 TAILQ_REMOVE(&requests, req, tq); 1592 free(req); 1593 num_req--; 1594 } else { 1595 /* Resend the request for the missing data */ 1596 debug3("Short data block, re-requesting " 1597 "%llu -> %llu (%2d)", 1598 (unsigned long long)req->offset + len, 1599 (unsigned long long)req->offset + 1600 req->len - 1, num_req); 1601 req->id = conn->msg_id++; 1602 req->len -= len; 1603 req->offset += len; 1604 send_read_request(conn, req->id, 1605 req->offset, req->len, handle, handle_len); 1606 /* Reduce the request size */ 1607 if (len < buflen) 1608 buflen = MAXIMUM(MIN_READ_SIZE, len); 1609 } 1610 if (max_req > 0) { /* max_req = 0 iff EOF received */ 1611 if (size > 0 && offset > size) { 1612 /* Only one request at a time 1613 * after the expected EOF */ 1614 debug3("Finish at %llu (%2d)", 1615 (unsigned long long)offset, 1616 num_req); 1617 max_req = 1; 1618 } else if (max_req < conn->num_requests) { 1619 ++max_req; 1620 } 1621 } 1622 break; 1623 default: 1624 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 1625 SSH2_FXP_DATA, type); 1626 } 1627 } 1628 1629 if (showprogress && size) 1630 stop_progress_meter(); 1631 1632 /* Sanity check */ 1633 if (TAILQ_FIRST(&requests) != NULL) 1634 fatal("Transfer complete, but requests still in queue"); 1635 /* Truncate at highest contiguous point to avoid holes on interrupt */ 1636 if (read_error || write_error || interrupted) { 1637 if (reordered && resume_flag) { 1638 error("Unable to resume download of \"%s\": " 1639 "server reordered requests", local_path); 1640 } 1641 debug("truncating at %llu", (unsigned long long)highwater); 1642 if (ftruncate(local_fd, highwater) == -1) 1643 error("ftruncate \"%s\": %s", local_path, 1644 strerror(errno)); 1645 } 1646 if (read_error) { 1647 error("Couldn't read from remote file \"%s\" : %s", 1648 remote_path, fx2txt(status)); 1649 status = -1; 1650 do_close(conn, handle, handle_len); 1651 } else if (write_error) { 1652 error("Couldn't write to \"%s\": %s", local_path, 1653 strerror(write_errno)); 1654 status = SSH2_FX_FAILURE; 1655 do_close(conn, handle, handle_len); 1656 } else { 1657 if (do_close(conn, handle, handle_len) != 0 || interrupted) 1658 status = SSH2_FX_FAILURE; 1659 else 1660 status = SSH2_FX_OK; 1661 /* Override umask and utimes if asked */ 1662 #ifdef HAVE_FCHMOD 1663 if (preserve_flag && fchmod(local_fd, mode) == -1) 1664 #else 1665 if (preserve_flag && chmod(local_path, mode) == -1) 1666 #endif /* HAVE_FCHMOD */ 1667 error("Couldn't set mode on \"%s\": %s", local_path, 1668 strerror(errno)); 1669 if (preserve_flag && 1670 (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 1671 struct timeval tv[2]; 1672 tv[0].tv_sec = a->atime; 1673 tv[1].tv_sec = a->mtime; 1674 tv[0].tv_usec = tv[1].tv_usec = 0; 1675 if (utimes(local_path, tv) == -1) 1676 error("Can't set times on \"%s\": %s", 1677 local_path, strerror(errno)); 1678 } 1679 if (resume_flag && !lmodified) 1680 logit("File \"%s\" was not modified", local_path); 1681 else if (fsync_flag) { 1682 debug("syncing \"%s\"", local_path); 1683 if (fsync(local_fd) == -1) 1684 error("Couldn't sync file \"%s\": %s", 1685 local_path, strerror(errno)); 1686 } 1687 } 1688 close(local_fd); 1689 sshbuf_free(msg); 1690 free(handle); 1691 1692 return status == SSH2_FX_OK ? 0 : -1; 1693 } 1694 1695 static int 1696 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 1697 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 1698 int resume_flag, int fsync_flag, int follow_link_flag) 1699 { 1700 int i, ret = 0; 1701 SFTP_DIRENT **dir_entries; 1702 char *filename, *new_src = NULL, *new_dst = NULL; 1703 mode_t mode = 0777, tmpmode = mode; 1704 1705 if (depth >= MAX_DIR_DEPTH) { 1706 error("Maximum directory depth exceeded: %d levels", depth); 1707 return -1; 1708 } 1709 1710 if (dirattrib == NULL && 1711 (dirattrib = do_stat(conn, src, 1)) == NULL) { 1712 error("Unable to stat remote directory \"%s\"", src); 1713 return -1; 1714 } 1715 if (!S_ISDIR(dirattrib->perm)) { 1716 error("\"%s\" is not a directory", src); 1717 return -1; 1718 } 1719 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 1720 mprintf("Retrieving %s\n", src); 1721 1722 if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 1723 mode = dirattrib->perm & 01777; 1724 tmpmode = mode | (S_IWUSR|S_IXUSR); 1725 } else { 1726 debug("Server did not send permissions for " 1727 "directory \"%s\"", dst); 1728 } 1729 1730 if (mkdir(dst, tmpmode) == -1 && errno != EEXIST) { 1731 error("mkdir %s: %s", dst, strerror(errno)); 1732 return -1; 1733 } 1734 1735 if (do_readdir(conn, src, &dir_entries) == -1) { 1736 error("%s: Failed to get directory contents", src); 1737 return -1; 1738 } 1739 1740 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 1741 free(new_dst); 1742 free(new_src); 1743 1744 filename = dir_entries[i]->filename; 1745 new_dst = path_append(dst, filename); 1746 new_src = path_append(src, filename); 1747 1748 if (S_ISDIR(dir_entries[i]->a.perm)) { 1749 if (strcmp(filename, ".") == 0 || 1750 strcmp(filename, "..") == 0) 1751 continue; 1752 if (download_dir_internal(conn, new_src, new_dst, 1753 depth + 1, &(dir_entries[i]->a), preserve_flag, 1754 print_flag, resume_flag, 1755 fsync_flag, follow_link_flag) == -1) 1756 ret = -1; 1757 } else if (S_ISREG(dir_entries[i]->a.perm) || 1758 (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { 1759 /* 1760 * If this is a symlink then don't send the link's 1761 * Attrib. do_download() will do a FXP_STAT operation 1762 * and get the link target's attributes. 1763 */ 1764 if (do_download(conn, new_src, new_dst, 1765 S_ISLNK(dir_entries[i]->a.perm) ? NULL : 1766 &(dir_entries[i]->a), 1767 preserve_flag, resume_flag, fsync_flag) == -1) { 1768 error("Download of file %s to %s failed", 1769 new_src, new_dst); 1770 ret = -1; 1771 } 1772 } else 1773 logit("%s: not a regular file\n", new_src); 1774 1775 } 1776 free(new_dst); 1777 free(new_src); 1778 1779 if (preserve_flag) { 1780 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1781 struct timeval tv[2]; 1782 tv[0].tv_sec = dirattrib->atime; 1783 tv[1].tv_sec = dirattrib->mtime; 1784 tv[0].tv_usec = tv[1].tv_usec = 0; 1785 if (utimes(dst, tv) == -1) 1786 error("Can't set times on \"%s\": %s", 1787 dst, strerror(errno)); 1788 } else 1789 debug("Server did not send times for directory " 1790 "\"%s\"", dst); 1791 } 1792 1793 if (mode != tmpmode && chmod(dst, mode) == -1) 1794 error("Can't set final mode on \"%s\": %s", dst, 1795 strerror(errno)); 1796 1797 free_sftp_dirents(dir_entries); 1798 1799 return ret; 1800 } 1801 1802 int 1803 download_dir(struct sftp_conn *conn, const char *src, const char *dst, 1804 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, 1805 int fsync_flag, int follow_link_flag) 1806 { 1807 char *src_canon; 1808 int ret; 1809 1810 if ((src_canon = do_realpath(conn, src)) == NULL) { 1811 error("Unable to canonicalize path \"%s\"", src); 1812 return -1; 1813 } 1814 1815 ret = download_dir_internal(conn, src_canon, dst, 0, 1816 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, 1817 follow_link_flag); 1818 free(src_canon); 1819 return ret; 1820 } 1821 1822 int 1823 do_upload(struct sftp_conn *conn, const char *local_path, 1824 const char *remote_path, int preserve_flag, int resume, int fsync_flag) 1825 { 1826 int r, local_fd; 1827 u_int status = SSH2_FX_OK; 1828 u_int id; 1829 u_char type; 1830 off_t offset, progress_counter; 1831 u_char *handle, *data; 1832 struct sshbuf *msg; 1833 struct stat sb; 1834 Attrib a, *c = NULL; 1835 u_int32_t startid; 1836 u_int32_t ackid; 1837 struct request *ack = NULL; 1838 struct requests acks; 1839 size_t handle_len; 1840 1841 TAILQ_INIT(&acks); 1842 1843 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 1844 error("Couldn't open local file \"%s\" for reading: %s", 1845 local_path, strerror(errno)); 1846 return(-1); 1847 } 1848 if (fstat(local_fd, &sb) == -1) { 1849 error("Couldn't fstat local file \"%s\": %s", 1850 local_path, strerror(errno)); 1851 close(local_fd); 1852 return(-1); 1853 } 1854 if (!S_ISREG(sb.st_mode)) { 1855 error("%s is not a regular file", local_path); 1856 close(local_fd); 1857 return(-1); 1858 } 1859 stat_to_attrib(&sb, &a); 1860 1861 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 1862 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 1863 a.perm &= 0777; 1864 if (!preserve_flag) 1865 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1866 1867 if (resume) { 1868 /* Get remote file size if it exists */ 1869 if ((c = do_stat(conn, remote_path, 0)) == NULL) { 1870 close(local_fd); 1871 return -1; 1872 } 1873 1874 if ((off_t)c->size >= sb.st_size) { 1875 error("destination file bigger or same size as " 1876 "source file"); 1877 close(local_fd); 1878 return -1; 1879 } 1880 1881 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { 1882 close(local_fd); 1883 return -1; 1884 } 1885 } 1886 1887 /* Send open request */ 1888 if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT| 1889 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC), 1890 &a, &handle, &handle_len) != 0) { 1891 close(local_fd); 1892 return -1; 1893 } 1894 1895 id = conn->msg_id; 1896 startid = ackid = id + 1; 1897 data = xmalloc(conn->upload_buflen); 1898 1899 /* Read from local and write to remote */ 1900 offset = progress_counter = (resume ? c->size : 0); 1901 if (showprogress) { 1902 start_progress_meter(progress_meter_path(local_path), 1903 sb.st_size, &progress_counter); 1904 } 1905 1906 if ((msg = sshbuf_new()) == NULL) 1907 fatal_f("sshbuf_new failed"); 1908 for (;;) { 1909 int len; 1910 1911 /* 1912 * Can't use atomicio here because it returns 0 on EOF, 1913 * thus losing the last block of the file. 1914 * Simulate an EOF on interrupt, allowing ACKs from the 1915 * server to drain. 1916 */ 1917 if (interrupted || status != SSH2_FX_OK) 1918 len = 0; 1919 else do 1920 len = read(local_fd, data, conn->upload_buflen); 1921 while ((len == -1) && 1922 (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); 1923 1924 if (len == -1) 1925 fatal("Couldn't read from \"%s\": %s", local_path, 1926 strerror(errno)); 1927 1928 if (len != 0) { 1929 ack = request_enqueue(&acks, ++id, len, offset); 1930 sshbuf_reset(msg); 1931 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 1932 (r = sshbuf_put_u32(msg, ack->id)) != 0 || 1933 (r = sshbuf_put_string(msg, handle, 1934 handle_len)) != 0 || 1935 (r = sshbuf_put_u64(msg, offset)) != 0 || 1936 (r = sshbuf_put_string(msg, data, len)) != 0) 1937 fatal_fr(r, "compose"); 1938 send_msg(conn, msg); 1939 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 1940 id, (unsigned long long)offset, len); 1941 } else if (TAILQ_FIRST(&acks) == NULL) 1942 break; 1943 1944 if (ack == NULL) 1945 fatal("Unexpected ACK %u", id); 1946 1947 if (id == startid || len == 0 || 1948 id - ackid >= conn->num_requests) { 1949 u_int rid; 1950 1951 sshbuf_reset(msg); 1952 get_msg(conn, msg); 1953 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 1954 (r = sshbuf_get_u32(msg, &rid)) != 0) 1955 fatal_fr(r, "parse"); 1956 1957 if (type != SSH2_FXP_STATUS) 1958 fatal("Expected SSH2_FXP_STATUS(%d) packet, " 1959 "got %d", SSH2_FXP_STATUS, type); 1960 1961 if ((r = sshbuf_get_u32(msg, &status)) != 0) 1962 fatal_fr(r, "parse status"); 1963 debug3("SSH2_FXP_STATUS %u", status); 1964 1965 /* Find the request in our queue */ 1966 if ((ack = request_find(&acks, rid)) == NULL) 1967 fatal("Can't find request for ID %u", rid); 1968 TAILQ_REMOVE(&acks, ack, tq); 1969 debug3("In write loop, ack for %u %zu bytes at %lld", 1970 ack->id, ack->len, (unsigned long long)ack->offset); 1971 ++ackid; 1972 progress_counter += ack->len; 1973 free(ack); 1974 } 1975 offset += len; 1976 if (offset < 0) 1977 fatal_f("offset < 0"); 1978 } 1979 sshbuf_free(msg); 1980 1981 if (showprogress) 1982 stop_progress_meter(); 1983 free(data); 1984 1985 if (status != SSH2_FX_OK) { 1986 error("Couldn't write to remote file \"%s\": %s", 1987 remote_path, fx2txt(status)); 1988 status = SSH2_FX_FAILURE; 1989 } 1990 1991 if (close(local_fd) == -1) { 1992 error("Couldn't close local file \"%s\": %s", local_path, 1993 strerror(errno)); 1994 status = SSH2_FX_FAILURE; 1995 } 1996 1997 /* Override umask and utimes if asked */ 1998 if (preserve_flag) 1999 do_fsetstat(conn, handle, handle_len, &a); 2000 2001 if (fsync_flag) 2002 (void)do_fsync(conn, handle, handle_len); 2003 2004 if (do_close(conn, handle, handle_len) != 0) 2005 status = SSH2_FX_FAILURE; 2006 2007 free(handle); 2008 2009 return status == SSH2_FX_OK ? 0 : -1; 2010 } 2011 2012 static int 2013 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, 2014 int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, 2015 int follow_link_flag) 2016 { 2017 int ret = 0; 2018 DIR *dirp; 2019 struct dirent *dp; 2020 char *filename, *new_src = NULL, *new_dst = NULL; 2021 struct stat sb; 2022 Attrib a, *dirattrib; 2023 u_int32_t saved_perm; 2024 2025 if (depth >= MAX_DIR_DEPTH) { 2026 error("Maximum directory depth exceeded: %d levels", depth); 2027 return -1; 2028 } 2029 2030 if (stat(src, &sb) == -1) { 2031 error("Couldn't stat directory \"%s\": %s", 2032 src, strerror(errno)); 2033 return -1; 2034 } 2035 if (!S_ISDIR(sb.st_mode)) { 2036 error("\"%s\" is not a directory", src); 2037 return -1; 2038 } 2039 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 2040 mprintf("Entering %s\n", src); 2041 2042 stat_to_attrib(&sb, &a); 2043 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2044 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2045 a.perm &= 01777; 2046 if (!preserve_flag) 2047 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 2048 2049 /* 2050 * sftp lacks a portable status value to match errno EEXIST, 2051 * so if we get a failure back then we must check whether 2052 * the path already existed and is a directory. Ensure we can 2053 * write to the directory we create for the duration of the transfer. 2054 */ 2055 saved_perm = a.perm; 2056 a.perm |= (S_IWUSR|S_IXUSR); 2057 if (do_mkdir(conn, dst, &a, 0) != 0) { 2058 if ((dirattrib = do_stat(conn, dst, 0)) == NULL) 2059 return -1; 2060 if (!S_ISDIR(dirattrib->perm)) { 2061 error("\"%s\" exists but is not a directory", dst); 2062 return -1; 2063 } 2064 } 2065 a.perm = saved_perm; 2066 2067 if ((dirp = opendir(src)) == NULL) { 2068 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 2069 return -1; 2070 } 2071 2072 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 2073 if (dp->d_ino == 0) 2074 continue; 2075 free(new_dst); 2076 free(new_src); 2077 filename = dp->d_name; 2078 new_dst = path_append(dst, filename); 2079 new_src = path_append(src, filename); 2080 2081 if (lstat(new_src, &sb) == -1) { 2082 logit("%s: lstat failed: %s", filename, 2083 strerror(errno)); 2084 ret = -1; 2085 } else if (S_ISDIR(sb.st_mode)) { 2086 if (strcmp(filename, ".") == 0 || 2087 strcmp(filename, "..") == 0) 2088 continue; 2089 2090 if (upload_dir_internal(conn, new_src, new_dst, 2091 depth + 1, preserve_flag, print_flag, resume, 2092 fsync_flag, follow_link_flag) == -1) 2093 ret = -1; 2094 } else if (S_ISREG(sb.st_mode) || 2095 (follow_link_flag && S_ISLNK(sb.st_mode))) { 2096 if (do_upload(conn, new_src, new_dst, 2097 preserve_flag, resume, fsync_flag) == -1) { 2098 error("Uploading of file %s to %s failed!", 2099 new_src, new_dst); 2100 ret = -1; 2101 } 2102 } else 2103 logit("%s: not a regular file\n", filename); 2104 } 2105 free(new_dst); 2106 free(new_src); 2107 2108 do_setstat(conn, dst, &a); 2109 2110 (void) closedir(dirp); 2111 return ret; 2112 } 2113 2114 int 2115 upload_dir(struct sftp_conn *conn, const char *src, const char *dst, 2116 int preserve_flag, int print_flag, int resume, int fsync_flag, 2117 int follow_link_flag) 2118 { 2119 char *dst_canon; 2120 int ret; 2121 2122 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 2123 error("Unable to canonicalize path \"%s\"", dst); 2124 return -1; 2125 } 2126 2127 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 2128 print_flag, resume, fsync_flag, follow_link_flag); 2129 2130 free(dst_canon); 2131 return ret; 2132 } 2133 2134 static void 2135 handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous, 2136 u_int *nreqsp, u_int *write_errorp) 2137 { 2138 struct sshbuf *msg; 2139 u_char type; 2140 u_int id, status; 2141 int r; 2142 struct pollfd pfd; 2143 2144 if ((msg = sshbuf_new()) == NULL) 2145 fatal_f("sshbuf_new failed"); 2146 2147 /* Try to eat replies from the upload side */ 2148 while (*nreqsp > 0) { 2149 debug3_f("%u outstanding replies", *nreqsp); 2150 if (!synchronous) { 2151 /* Bail out if no data is ready to be read */ 2152 pfd.fd = to->fd_in; 2153 pfd.events = POLLIN; 2154 if ((r = poll(&pfd, 1, 0)) == -1) { 2155 if (errno == EINTR) 2156 break; 2157 fatal_f("poll: %s", strerror(errno)); 2158 } else if (r == 0) 2159 break; /* fd not ready */ 2160 } 2161 sshbuf_reset(msg); 2162 get_msg(to, msg); 2163 2164 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 2165 (r = sshbuf_get_u32(msg, &id)) != 0) 2166 fatal_fr(r, "dest parse"); 2167 debug3("Received dest reply T:%u I:%u R:%u", type, id, *nreqsp); 2168 if (type != SSH2_FXP_STATUS) { 2169 fatal_f("Expected SSH2_FXP_STATUS(%d) packet, got %d", 2170 SSH2_FXP_STATUS, type); 2171 } 2172 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2173 fatal_fr(r, "parse dest status"); 2174 debug3("dest SSH2_FXP_STATUS %u", status); 2175 if (status != SSH2_FX_OK) { 2176 /* record first error */ 2177 if (*write_errorp == 0) 2178 *write_errorp = status; 2179 } 2180 /* 2181 * XXX this doesn't do full reply matching like do_upload and 2182 * so cannot gracefully truncate terminated uploads at a 2183 * high-water mark. ATM the only caller of this function (scp) 2184 * doesn't support transfer resumption, so this doesn't matter 2185 * a whole lot. 2186 * 2187 * To be safe, do_crossload truncates the destination file to 2188 * zero length on upload failure, since we can't trust the 2189 * server not to have reordered replies that could have 2190 * inserted holes where none existed in the source file. 2191 * 2192 * XXX we could get a more accutate progress bar if we updated 2193 * the counter based on the reply from the destination... 2194 */ 2195 (*nreqsp)--; 2196 } 2197 debug3_f("done: %u outstanding replies", *nreqsp); 2198 } 2199 2200 int 2201 do_crossload(struct sftp_conn *from, struct sftp_conn *to, 2202 const char *from_path, const char *to_path, 2203 Attrib *a, int preserve_flag) 2204 { 2205 struct sshbuf *msg; 2206 int write_error, read_error, r; 2207 u_int64_t offset = 0, size; 2208 u_int id, buflen, num_req, max_req, status = SSH2_FX_OK; 2209 u_int num_upload_req; 2210 off_t progress_counter; 2211 u_char *from_handle, *to_handle; 2212 size_t from_handle_len, to_handle_len; 2213 struct requests requests; 2214 struct request *req; 2215 u_char type; 2216 2217 TAILQ_INIT(&requests); 2218 2219 if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL) 2220 return -1; 2221 2222 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 2223 (!S_ISREG(a->perm))) { 2224 error("Cannot download non-regular file: %s", from_path); 2225 return(-1); 2226 } 2227 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 2228 size = a->size; 2229 else 2230 size = 0; 2231 2232 buflen = from->download_buflen; 2233 if (buflen > to->upload_buflen) 2234 buflen = to->upload_buflen; 2235 2236 /* Send open request to read side */ 2237 if (send_open(from, from_path, "origin", SSH2_FXF_READ, NULL, 2238 &from_handle, &from_handle_len) != 0) 2239 return -1; 2240 2241 /* Send open request to write side */ 2242 a->flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2243 a->flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2244 a->perm &= 0777; 2245 if (!preserve_flag) 2246 a->flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 2247 if (send_open(to, to_path, "dest", 2248 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, 2249 &to_handle, &to_handle_len) != 0) { 2250 do_close(from, from_handle, from_handle_len); 2251 return -1; 2252 } 2253 2254 /* Read from remote "from" and write to remote "to" */ 2255 offset = 0; 2256 write_error = read_error = num_req = num_upload_req = 0; 2257 max_req = 1; 2258 progress_counter = 0; 2259 2260 if (showprogress && size != 0) { 2261 start_progress_meter(progress_meter_path(from_path), 2262 size, &progress_counter); 2263 } 2264 if ((msg = sshbuf_new()) == NULL) 2265 fatal_f("sshbuf_new failed"); 2266 while (num_req > 0 || max_req > 0) { 2267 u_char *data; 2268 size_t len; 2269 2270 /* 2271 * Simulate EOF on interrupt: stop sending new requests and 2272 * allow outstanding requests to drain gracefully 2273 */ 2274 if (interrupted) { 2275 if (num_req == 0) /* If we haven't started yet... */ 2276 break; 2277 max_req = 0; 2278 } 2279 2280 /* Send some more requests */ 2281 while (num_req < max_req) { 2282 debug3("Request range %llu -> %llu (%d/%d)", 2283 (unsigned long long)offset, 2284 (unsigned long long)offset + buflen - 1, 2285 num_req, max_req); 2286 req = request_enqueue(&requests, from->msg_id++, 2287 buflen, offset); 2288 offset += buflen; 2289 num_req++; 2290 send_read_request(from, req->id, req->offset, 2291 req->len, from_handle, from_handle_len); 2292 } 2293 2294 /* Try to eat replies from the upload side (nonblocking) */ 2295 handle_dest_replies(to, to_path, 0, 2296 &num_upload_req, &write_error); 2297 2298 sshbuf_reset(msg); 2299 get_msg(from, msg); 2300 if ((r = sshbuf_get_u8(msg, &type)) != 0 || 2301 (r = sshbuf_get_u32(msg, &id)) != 0) 2302 fatal_fr(r, "parse"); 2303 debug3("Received origin reply T:%u I:%u R:%d", 2304 type, id, max_req); 2305 2306 /* Find the request in our queue */ 2307 if ((req = request_find(&requests, id)) == NULL) 2308 fatal("Unexpected reply %u", id); 2309 2310 switch (type) { 2311 case SSH2_FXP_STATUS: 2312 if ((r = sshbuf_get_u32(msg, &status)) != 0) 2313 fatal_fr(r, "parse status"); 2314 if (status != SSH2_FX_EOF) 2315 read_error = 1; 2316 max_req = 0; 2317 TAILQ_REMOVE(&requests, req, tq); 2318 free(req); 2319 num_req--; 2320 break; 2321 case SSH2_FXP_DATA: 2322 if ((r = sshbuf_get_string(msg, &data, &len)) != 0) 2323 fatal_fr(r, "parse data"); 2324 debug3("Received data %llu -> %llu", 2325 (unsigned long long)req->offset, 2326 (unsigned long long)req->offset + len - 1); 2327 if (len > req->len) 2328 fatal("Received more data than asked for " 2329 "%zu > %zu", len, req->len); 2330 2331 /* Write this chunk out to the destination */ 2332 sshbuf_reset(msg); 2333 if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || 2334 (r = sshbuf_put_u32(msg, to->msg_id++)) != 0 || 2335 (r = sshbuf_put_string(msg, to_handle, 2336 to_handle_len)) != 0 || 2337 (r = sshbuf_put_u64(msg, req->offset)) != 0 || 2338 (r = sshbuf_put_string(msg, data, len)) != 0) 2339 fatal_fr(r, "compose write"); 2340 send_msg(to, msg); 2341 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%zu", 2342 id, (unsigned long long)offset, len); 2343 num_upload_req++; 2344 progress_counter += len; 2345 free(data); 2346 2347 if (len == req->len) { 2348 TAILQ_REMOVE(&requests, req, tq); 2349 free(req); 2350 num_req--; 2351 } else { 2352 /* Resend the request for the missing data */ 2353 debug3("Short data block, re-requesting " 2354 "%llu -> %llu (%2d)", 2355 (unsigned long long)req->offset + len, 2356 (unsigned long long)req->offset + 2357 req->len - 1, num_req); 2358 req->id = from->msg_id++; 2359 req->len -= len; 2360 req->offset += len; 2361 send_read_request(from, req->id, 2362 req->offset, req->len, 2363 from_handle, from_handle_len); 2364 /* Reduce the request size */ 2365 if (len < buflen) 2366 buflen = MAXIMUM(MIN_READ_SIZE, len); 2367 } 2368 if (max_req > 0) { /* max_req = 0 iff EOF received */ 2369 if (size > 0 && offset > size) { 2370 /* Only one request at a time 2371 * after the expected EOF */ 2372 debug3("Finish at %llu (%2d)", 2373 (unsigned long long)offset, 2374 num_req); 2375 max_req = 1; 2376 } else if (max_req < from->num_requests) { 2377 ++max_req; 2378 } 2379 } 2380 break; 2381 default: 2382 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 2383 SSH2_FXP_DATA, type); 2384 } 2385 } 2386 2387 if (showprogress && size) 2388 stop_progress_meter(); 2389 2390 /* Drain replies from the server (blocking) */ 2391 debug3_f("waiting for %u replies from destination", num_upload_req); 2392 handle_dest_replies(to, to_path, 1, &num_upload_req, &write_error); 2393 2394 /* Sanity check */ 2395 if (TAILQ_FIRST(&requests) != NULL) 2396 fatal("Transfer complete, but requests still in queue"); 2397 /* Truncate at 0 length on interrupt or error to avoid holes at dest */ 2398 if (read_error || write_error || interrupted) { 2399 debug("truncating \"%s\" at 0", to_path); 2400 do_close(to, to_handle, to_handle_len); 2401 free(to_handle); 2402 if (send_open(to, to_path, "dest", 2403 SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, 2404 &to_handle, &to_handle_len) != 0) { 2405 error("truncation failed for \"%s\"", to_path); 2406 to_handle = NULL; 2407 } 2408 } 2409 if (read_error) { 2410 error("Couldn't read from origin file \"%s\" : %s", 2411 from_path, fx2txt(status)); 2412 status = -1; 2413 do_close(from, from_handle, from_handle_len); 2414 if (to_handle != NULL) 2415 do_close(to, to_handle, to_handle_len); 2416 } else if (write_error) { 2417 error("Couldn't write to \"%s\": %s", 2418 to_path, fx2txt(write_error)); 2419 status = SSH2_FX_FAILURE; 2420 do_close(from, from_handle, from_handle_len); 2421 if (to_handle != NULL) 2422 do_close(to, to_handle, to_handle_len); 2423 } else { 2424 if (do_close(from, from_handle, from_handle_len) != 0 || 2425 interrupted) 2426 status = -1; 2427 else 2428 status = SSH2_FX_OK; 2429 if (to_handle != NULL) { 2430 /* Need to resend utimes after write */ 2431 if (preserve_flag) 2432 do_fsetstat(to, to_handle, to_handle_len, a); 2433 do_close(to, to_handle, to_handle_len); 2434 } 2435 } 2436 sshbuf_free(msg); 2437 free(from_handle); 2438 free(to_handle); 2439 2440 return status == SSH2_FX_OK ? 0 : -1; 2441 } 2442 2443 static int 2444 crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, 2445 const char *from_path, const char *to_path, 2446 int depth, Attrib *dirattrib, int preserve_flag, int print_flag, 2447 int follow_link_flag) 2448 { 2449 int i, ret = 0; 2450 SFTP_DIRENT **dir_entries; 2451 char *filename, *new_from_path = NULL, *new_to_path = NULL; 2452 mode_t mode = 0777; 2453 Attrib curdir; 2454 2455 if (depth >= MAX_DIR_DEPTH) { 2456 error("Maximum directory depth exceeded: %d levels", depth); 2457 return -1; 2458 } 2459 2460 if (dirattrib == NULL && 2461 (dirattrib = do_stat(from, from_path, 1)) == NULL) { 2462 error("Unable to stat remote directory \"%s\"", from_path); 2463 return -1; 2464 } 2465 if (!S_ISDIR(dirattrib->perm)) { 2466 error("\"%s\" is not a directory", from_path); 2467 return -1; 2468 } 2469 if (print_flag && print_flag != SFTP_PROGRESS_ONLY) 2470 mprintf("Retrieving %s\n", from_path); 2471 2472 curdir = *dirattrib; /* dirattrib will be clobbered */ 2473 curdir.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 2474 curdir.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 2475 if ((curdir.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) == 0) { 2476 debug("Origin did not send permissions for " 2477 "directory \"%s\"", to_path); 2478 curdir.perm = S_IWUSR|S_IXUSR; 2479 curdir.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 2480 } 2481 /* We need to be able to write to the directory while we transfer it */ 2482 mode = curdir.perm & 01777; 2483 curdir.perm = mode | (S_IWUSR|S_IXUSR); 2484 2485 /* 2486 * sftp lacks a portable status value to match errno EEXIST, 2487 * so if we get a failure back then we must check whether 2488 * the path already existed and is a directory. Ensure we can 2489 * write to the directory we create for the duration of the transfer. 2490 */ 2491 if (do_mkdir(to, to_path, &curdir, 0) != 0) { 2492 if ((dirattrib = do_stat(to, to_path, 0)) == NULL) 2493 return -1; 2494 if (!S_ISDIR(dirattrib->perm)) { 2495 error("\"%s\" exists but is not a directory", to_path); 2496 return -1; 2497 } 2498 } 2499 curdir.perm = mode; 2500 2501 if (do_readdir(from, from_path, &dir_entries) == -1) { 2502 error("%s: Failed to get directory contents", from_path); 2503 return -1; 2504 } 2505 2506 for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 2507 free(new_from_path); 2508 free(new_to_path); 2509 2510 filename = dir_entries[i]->filename; 2511 new_from_path = path_append(from_path, filename); 2512 new_to_path = path_append(to_path, filename); 2513 2514 if (S_ISDIR(dir_entries[i]->a.perm)) { 2515 if (strcmp(filename, ".") == 0 || 2516 strcmp(filename, "..") == 0) 2517 continue; 2518 if (crossload_dir_internal(from, to, 2519 new_from_path, new_to_path, 2520 depth + 1, &(dir_entries[i]->a), preserve_flag, 2521 print_flag, follow_link_flag) == -1) 2522 ret = -1; 2523 } else if (S_ISREG(dir_entries[i]->a.perm) || 2524 (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { 2525 /* 2526 * If this is a symlink then don't send the link's 2527 * Attrib. do_download() will do a FXP_STAT operation 2528 * and get the link target's attributes. 2529 */ 2530 if (do_crossload(from, to, new_from_path, new_to_path, 2531 S_ISLNK(dir_entries[i]->a.perm) ? NULL : 2532 &(dir_entries[i]->a), preserve_flag) == -1) { 2533 error("Transfer of file %s to %s failed", 2534 new_from_path, new_to_path); 2535 ret = -1; 2536 } 2537 } else 2538 logit("%s: not a regular file\n", new_from_path); 2539 2540 } 2541 free(new_to_path); 2542 free(new_from_path); 2543 2544 do_setstat(to, to_path, &curdir); 2545 2546 free_sftp_dirents(dir_entries); 2547 2548 return ret; 2549 } 2550 2551 int 2552 crossload_dir(struct sftp_conn *from, struct sftp_conn *to, 2553 const char *from_path, const char *to_path, 2554 Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag) 2555 { 2556 char *from_path_canon; 2557 int ret; 2558 2559 if ((from_path_canon = do_realpath(from, from_path)) == NULL) { 2560 error("Unable to canonicalize path \"%s\"", from_path); 2561 return -1; 2562 } 2563 2564 ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0, 2565 dirattrib, preserve_flag, print_flag, follow_link_flag); 2566 free(from_path_canon); 2567 return ret; 2568 } 2569 2570 char * 2571 path_append(const char *p1, const char *p2) 2572 { 2573 char *ret; 2574 size_t len = strlen(p1) + strlen(p2) + 2; 2575 2576 ret = xmalloc(len); 2577 strlcpy(ret, p1, len); 2578 if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 2579 strlcat(ret, "/", len); 2580 strlcat(ret, p2, len); 2581 2582 return(ret); 2583 } 2584 2585 char * 2586 make_absolute(char *p, const char *pwd) 2587 { 2588 char *abs_str; 2589 2590 /* Derelativise */ 2591 if (p && !path_absolute(p)) { 2592 abs_str = path_append(pwd, p); 2593 free(p); 2594 return(abs_str); 2595 } else 2596 return(p); 2597 } 2598 2599 int 2600 remote_is_dir(struct sftp_conn *conn, const char *path) 2601 { 2602 Attrib *a; 2603 2604 /* XXX: report errors? */ 2605 if ((a = do_stat(conn, path, 1)) == NULL) 2606 return(0); 2607 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 2608 return(0); 2609 return(S_ISDIR(a->perm)); 2610 } 2611 2612 2613 int 2614 local_is_dir(const char *path) 2615 { 2616 struct stat sb; 2617 2618 /* XXX: report errors? */ 2619 if (stat(path, &sb) == -1) 2620 return(0); 2621 2622 return(S_ISDIR(sb.st_mode)); 2623 } 2624 2625 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 2626 int 2627 globpath_is_dir(const char *pathname) 2628 { 2629 size_t l = strlen(pathname); 2630 2631 return l > 0 && pathname[l - 1] == '/'; 2632 } 2633 2634