diff --git a/scp.c b/scp.c index 5edb4f07d..55c018770 100644 --- a/scp.c +++ b/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.257 2023/07/14 05:31:44 djm Exp $ */ +/* $OpenBSD: scp.c,v 1.258 2023/09/08 05:56:13 djm Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -1028,7 +1028,7 @@ do_sftp_connect(char *host, char *user, int port, char *sftp_direct, reminp, remoutp, pidp) < 0) return NULL; } - return do_init(*reminp, *remoutp, + return sftp_init(*reminp, *remoutp, sftp_copy_buflen, sftp_nrequests, limit_kbps); } @@ -1324,8 +1324,8 @@ prepare_remote_path(struct sftp_conn *conn, const char *path) return xstrdup("."); return xstrdup(path + 2 + nslash); } - if (can_expand_path(conn)) - return do_expand_path(conn, path); + if (sftp_can_expand_path(conn)) + return sftp_expand_path(conn, path); /* No protocol extension */ error("server expand-path extension is required " "for ~user paths in SFTP mode"); @@ -1353,17 +1353,17 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) */ if ((target = prepare_remote_path(conn, targ)) == NULL) cleanup_exit(255); - target_is_dir = remote_is_dir(conn, target); + target_is_dir = sftp_remote_is_dir(conn, target); if (targetshouldbedirectory && !target_is_dir) { debug("target directory \"%s\" does not exist", target); a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = st.st_mode | 0700; /* ensure writable */ - if (do_mkdir(conn, target, &a, 1) != 0) + if (sftp_mkdir(conn, target, &a, 1) != 0) cleanup_exit(255); /* error already logged */ target_is_dir = 1; } if (target_is_dir) - abs_dst = path_append(target, filename); + abs_dst = sftp_path_append(target, filename); else { abs_dst = target; target = NULL; @@ -1371,12 +1371,12 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) debug3_f("copying local %s to remote %s", src, abs_dst); if (src_is_dir && iamrecursive) { - if (upload_dir(conn, src, abs_dst, pflag, + if (sftp_upload_dir(conn, src, abs_dst, pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { error("failed to upload directory %s to %s", src, targ); errs = 1; } - } else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) { + } else if (sftp_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) { error("failed to upload file %s to %s", src, targ); errs = 1; } @@ -1585,7 +1585,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn) * a GLOB_NOCHECK result. Check whether the unglobbed path * exists so we can give a nice error message early. */ - if (do_stat(conn, g.gl_pathv[0], 1) == NULL) { + if (sftp_stat(conn, g.gl_pathv[0], 1, NULL) != 0) { error("%s: %s", src, strerror(ENOENT)); err = -1; goto out; @@ -1621,17 +1621,17 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn) } if (dst_is_dir) - abs_dst = path_append(dst, filename); + abs_dst = sftp_path_append(dst, filename); else abs_dst = xstrdup(dst); debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); - if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { - if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, - pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1) + if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { + if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst, + NULL, pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1) err = -1; } else { - if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, + if (sftp_download(conn, g.gl_pathv[i], abs_dst, NULL, pflag, 0, 0, 1) == -1) err = -1; } @@ -1993,7 +1993,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to, cleanup_exit(255); memset(&g, 0, sizeof(g)); - targetisdir = remote_is_dir(to, target); + targetisdir = sftp_remote_is_dir(to, target); if (!targetisdir && targetshouldbedirectory) { error("%s: destination is not a directory", targ); err = -1; @@ -2018,7 +2018,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to, * a GLOB_NOCHECK result. Check whether the unglobbed path * exists so we can give a nice error message early. */ - if (do_stat(from, g.gl_pathv[0], 1) == NULL) { + if (sftp_stat(from, g.gl_pathv[0], 1, NULL) != 0) { error("%s: %s", src, strerror(ENOENT)); err = -1; goto out; @@ -2034,18 +2034,18 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to, } if (targetisdir) - abs_dst = path_append(target, filename); + abs_dst = sftp_path_append(target, filename); else abs_dst = xstrdup(target); debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); - if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { - if (crossload_dir(from, to, g.gl_pathv[i], abs_dst, + if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { + if (sftp_crossload_dir(from, to, g.gl_pathv[i], abs_dst, NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1) err = -1; } else { - if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL, - pflag) == -1) + if (sftp_crossload(from, to, g.gl_pathv[i], abs_dst, + NULL, pflag) == -1) err = -1; } free(abs_dst); diff --git a/sftp-client.c b/sftp-client.c index d6566a834..8153c3d2d 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.172 2023/09/08 05:50:12 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.173 2023/09/08 05:56:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -342,16 +342,17 @@ get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, return handle; } -/* XXX returning &static is error-prone. Refactor to fill *Attrib argument */ -static Attrib * -get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) +static int +get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet, Attrib *a) { struct sshbuf *msg; u_int id; u_char type; int r; - static Attrib a; + Attrib attr; + if (a != NULL) + memset(a, '\0', sizeof(*a)); if ((msg = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); get_msg(conn, msg); @@ -372,21 +373,24 @@ get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) else error("stat remote: %s", fx2txt(status)); sshbuf_free(msg); - return(NULL); + return -1; } else if (type != SSH2_FXP_ATTRS) { fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", SSH2_FXP_ATTRS, type); } - if ((r = decode_attrib(msg, &a)) != 0) { + if ((r = decode_attrib(msg, &attr)) != 0) { error_fr(r, "decode_attrib"); sshbuf_free(msg); - return NULL; + return -1; } + /* success */ + if (a != NULL) + *a = attr; debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o", - type, id, a.flags, a.perm); + type, id, attr.flags, attr.perm); sshbuf_free(msg); - return &a; + return 0; } static int @@ -449,7 +453,7 @@ get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, } struct sftp_conn * -do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, +sftp_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, u_int64_t limit_kbps) { u_char type; @@ -560,7 +564,7 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, /* Query the server for its limits */ if (ret->exts & SFTP_EXT_LIMITS) { struct sftp_limits limits; - if (do_limits(ret, &limits) != 0) + if (sftp_get_limits(ret, &limits) != 0) fatal_f("limits failed"); /* If the caller did not specify, find a good value */ @@ -614,7 +618,7 @@ sftp_proto_version(struct sftp_conn *conn) } int -do_limits(struct sftp_conn *conn, struct sftp_limits *limits) +sftp_get_limits(struct sftp_conn *conn, struct sftp_limits *limits) { u_int id, msg_id; u_char type; @@ -668,7 +672,7 @@ do_limits(struct sftp_conn *conn, struct sftp_limits *limits) } int -do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) +sftp_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) { u_int id, status; struct sshbuf *msg; @@ -696,7 +700,7 @@ do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) static int -do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, +sftp_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, SFTP_DIRENT ***dir) { struct sshbuf *msg; @@ -821,16 +825,16 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, out: sshbuf_free(msg); - do_close(conn, handle, handle_len); + sftp_close(conn, handle, handle_len); free(handle); if (status != 0 && dir != NULL) { /* Don't return results on error */ - free_sftp_dirents(*dir); + sftp_free_dirents(*dir); *dir = NULL; } else if (interrupted && dir != NULL && *dir != NULL) { /* Don't return partial matches on interrupt */ - free_sftp_dirents(*dir); + sftp_free_dirents(*dir); *dir = xcalloc(1, sizeof(**dir)); **dir = NULL; } @@ -839,12 +843,12 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, } int -do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) +sftp_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) { - return(do_lsreaddir(conn, path, 0, dir)); + return sftp_lsreaddir(conn, path, 0, dir); } -void free_sftp_dirents(SFTP_DIRENT **s) +void sftp_free_dirents(SFTP_DIRENT **s) { int i; @@ -859,7 +863,7 @@ void free_sftp_dirents(SFTP_DIRENT **s) } int -do_rm(struct sftp_conn *conn, const char *path) +sftp_rm(struct sftp_conn *conn, const char *path) { u_int status, id; @@ -874,7 +878,7 @@ do_rm(struct sftp_conn *conn, const char *path) } int -do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) +sftp_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) { u_int status, id; @@ -892,7 +896,7 @@ do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) } int -do_rmdir(struct sftp_conn *conn, const char *path) +sftp_rmdir(struct sftp_conn *conn, const char *path) { u_int status, id; @@ -909,8 +913,8 @@ do_rmdir(struct sftp_conn *conn, const char *path) return status == SSH2_FX_OK ? 0 : -1; } -Attrib * -do_stat(struct sftp_conn *conn, const char *path, int quiet) +int +sftp_stat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a) { u_int id; @@ -922,33 +926,31 @@ do_stat(struct sftp_conn *conn, const char *path, int quiet) conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, path, strlen(path)); - return(get_decode_stat(conn, id, quiet)); + return get_decode_stat(conn, id, quiet, a); } -Attrib * -do_lstat(struct sftp_conn *conn, const char *path, int quiet) +int +sftp_lstat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a) { u_int id; if (conn->version == 0) { - if (quiet) - debug("Server version does not support lstat operation"); - else - logit("Server version does not support lstat operation"); - return(do_stat(conn, path, quiet)); + do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO, + "Server version does not support lstat operation"); + return sftp_stat(conn, path, quiet, a); } id = conn->msg_id++; send_string_request(conn, id, SSH2_FXP_LSTAT, path, strlen(path)); - return(get_decode_stat(conn, id, quiet)); + return get_decode_stat(conn, id, quiet, a); } #ifdef notyet -Attrib * -do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, - int quiet) +int +sftp_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, + int quiet, Attrib *a) { u_int id; @@ -958,12 +960,12 @@ do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, send_string_request(conn, id, SSH2_FXP_FSTAT, handle, handle_len); - return(get_decode_stat(conn, id, quiet)); + return get_decode_stat(conn, id, quiet, a); } #endif int -do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) +sftp_setstat(struct sftp_conn *conn, const char *path, Attrib *a) { u_int status, id; @@ -981,7 +983,7 @@ do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) } int -do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, +sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, Attrib *a) { u_int status, id; @@ -1001,7 +1003,7 @@ do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, /* Implements both the realpath and expand-path operations */ static char * -do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) +sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) { struct sshbuf *msg; u_int expected_id, count, id; @@ -1076,31 +1078,31 @@ do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) } char * -do_realpath(struct sftp_conn *conn, const char *path) +sftp_realpath(struct sftp_conn *conn, const char *path) { - return do_realpath_expand(conn, path, 0); + return sftp_realpath_expand(conn, path, 0); } int -can_expand_path(struct sftp_conn *conn) +sftp_can_expand_path(struct sftp_conn *conn) { return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0; } char * -do_expand_path(struct sftp_conn *conn, const char *path) +sftp_expand_path(struct sftp_conn *conn, const char *path) { - if (!can_expand_path(conn)) { + if (!sftp_can_expand_path(conn)) { debug3_f("no server support, fallback to realpath"); - return do_realpath_expand(conn, path, 0); + return sftp_realpath_expand(conn, path, 0); } - return do_realpath_expand(conn, path, 1); + return sftp_realpath_expand(conn, path, 1); } int -do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) +sftp_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) { - Attrib junk, *a; + Attrib junk, attr; struct sshbuf *msg; u_char *old_handle, *new_handle; u_int mode, status, id; @@ -1114,14 +1116,14 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) } /* Make sure the file exists, and we can copy its perms */ - if ((a = do_stat(conn, oldpath, 0)) == NULL) + if (sftp_stat(conn, oldpath, 0, &attr) != 0) return -1; /* Do not preserve set[ug]id here, as we do not preserve ownership */ - if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { - mode = a->perm & 0777; + if (attr.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + mode = attr.perm & 0777; - if (!S_ISREG(a->perm)) { + if (!S_ISREG(attr.perm)) { error("Cannot copy non-regular file: %s", oldpath); return -1; } @@ -1131,9 +1133,9 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) } /* Set up the new perms for the new file */ - attrib_clear(a); - a->perm = mode; - a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + attrib_clear(&attr); + attr.perm = mode; + attr.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; if ((msg = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); @@ -1167,7 +1169,7 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) (r = sshbuf_put_cstring(msg, newpath)) != 0 || (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| SSH2_FXF_TRUNC)) != 0 || - (r = encode_attrib(msg, a)) != 0) + (r = encode_attrib(msg, &attr)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(conn, msg); debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath); @@ -1204,8 +1206,8 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) /* Clean up everything */ sshbuf_free(msg); - do_close(conn, old_handle, old_handle_len); - do_close(conn, new_handle, new_handle_len); + sftp_close(conn, old_handle, old_handle_len); + sftp_close(conn, new_handle, new_handle_len); free(old_handle); free(new_handle); @@ -1213,7 +1215,7 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) } int -do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, +sftp_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, int force_legacy) { struct sshbuf *msg; @@ -1258,7 +1260,7 @@ do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, } int -do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) +sftp_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) { struct sshbuf *msg; u_int status, id; @@ -1296,7 +1298,7 @@ do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) } int -do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) +sftp_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) { struct sshbuf *msg; u_int status, id; @@ -1332,7 +1334,7 @@ do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) } int -do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) +sftp_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) { struct sshbuf *msg; u_int status, id; @@ -1365,7 +1367,7 @@ do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) #ifdef notyet char * -do_readlink(struct sftp_conn *conn, const char *path) +sftp_readlink(struct sftp_conn *conn, const char *path) { struct sshbuf *msg; u_int expected_id, count, id; @@ -1423,7 +1425,7 @@ do_readlink(struct sftp_conn *conn, const char *path) #endif int -do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, +sftp_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, int quiet) { struct sshbuf *msg; @@ -1454,7 +1456,7 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, #ifdef notyet int -do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, +sftp_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, struct sftp_statvfs *st, int quiet) { struct sshbuf *msg; @@ -1484,7 +1486,7 @@ do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, #endif int -do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) +sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) { struct sshbuf *msg; u_int status, id; @@ -1592,7 +1594,7 @@ progress_meter_path(const char *path) } int -do_download(struct sftp_conn *conn, const char *remote_path, +sftp_download(struct sftp_conn *conn, const char *remote_path, const char *local_path, Attrib *a, int preserve_flag, int resume_flag, int fsync_flag, int inplace_flag) { @@ -1608,14 +1610,18 @@ do_download(struct sftp_conn *conn, const char *remote_path, struct requests requests; struct request *req; u_char type; + Attrib attr; debug2_f("download remote \"%s\" to local \"%s\"", remote_path, local_path); TAILQ_INIT(&requests); - if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) - return -1; + if (a == NULL) { + if (sftp_stat(conn, remote_path, 0, &attr) != 0) + return -1; + a = &attr; + } /* Do not preserve set[ug]id here, as we do not preserve ownership */ if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) @@ -1661,7 +1667,7 @@ do_download(struct sftp_conn *conn, const char *remote_path, error("Unable to resume download of \"%s\": " "local file is larger than remote", local_path); fail: - do_close(conn, handle, handle_len); + sftp_close(conn, handle, handle_len); free(handle); if (local_fd != -1) close(local_fd); @@ -1836,14 +1842,14 @@ do_download(struct sftp_conn *conn, const char *remote_path, if (read_error) { error("read remote \"%s\" : %s", remote_path, fx2txt(status)); status = -1; - do_close(conn, handle, handle_len); + sftp_close(conn, handle, handle_len); } else if (write_error) { error("write local \"%s\": %s", local_path, strerror(write_errno)); status = SSH2_FX_FAILURE; - do_close(conn, handle, handle_len); + sftp_close(conn, handle, handle_len); } else { - if (do_close(conn, handle, handle_len) != 0 || interrupted) + if (sftp_close(conn, handle, handle_len) != 0 || interrupted) status = SSH2_FX_FAILURE; else status = SSH2_FX_OK; @@ -1900,12 +1906,10 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst); if (dirattrib == NULL) { - if ((a = do_stat(conn, src, 1)) == NULL) { + if (sftp_stat(conn, src, 1, &ldirattrib) != 0) { error("stat remote \"%s\" directory failed", src); return -1; } - /* Don't let this be clobbered by later do_stat calls */ - ldirattrib = *a; dirattrib = &ldirattrib; } if (!S_ISDIR(dirattrib->perm)) { @@ -1928,7 +1932,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, return -1; } - if (do_readdir(conn, src, &dir_entries) == -1) { + if (sftp_readdir(conn, src, &dir_entries) == -1) { error("remote readdir \"%s\" failed", src); return -1; } @@ -1938,8 +1942,8 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, free(new_src); filename = dir_entries[i]->filename; - new_dst = path_append(dst, filename); - new_src = path_append(src, filename); + new_dst = sftp_path_append(dst, filename); + new_src = sftp_path_append(src, filename); a = &dir_entries[i]->a; if (S_ISLNK(a->perm)) { @@ -1949,13 +1953,11 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, continue; } /* Replace the stat contents with the symlink target */ - if ((a = do_stat(conn, new_src, 1)) == NULL) { + if (sftp_stat(conn, new_src, 1, &lsym) != 0) { logit("remote stat \"%s\" failed", new_src); ret = -1; continue; } - /* Don't let this be clobbered by later do_stat calls */ - lsym = *a; a = &lsym; } @@ -1969,7 +1971,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, fsync_flag, follow_link_flag, inplace_flag) == -1) ret = -1; } else if (S_ISREG(a->perm)) { - if (do_download(conn, new_src, new_dst, a, + if (sftp_download(conn, new_src, new_dst, a, preserve_flag, resume_flag, fsync_flag, inplace_flag) == -1) { error("Download of file %s to %s failed", @@ -2001,20 +2003,20 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, error("local chmod directory \"%s\": %s", dst, strerror(errno)); - free_sftp_dirents(dir_entries); + sftp_free_dirents(dir_entries); return ret; } int -download_dir(struct sftp_conn *conn, const char *src, const char *dst, +sftp_download_dir(struct sftp_conn *conn, const char *src, const char *dst, Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, int fsync_flag, int follow_link_flag, int inplace_flag) { char *src_canon; int ret; - if ((src_canon = do_realpath(conn, src)) == NULL) { + if ((src_canon = sftp_realpath(conn, src)) == NULL) { error("download \"%s\": path canonicalization failed", src); return -1; } @@ -2027,7 +2029,7 @@ download_dir(struct sftp_conn *conn, const char *src, const char *dst, } int -do_upload(struct sftp_conn *conn, const char *local_path, +sftp_upload(struct sftp_conn *conn, const char *local_path, const char *remote_path, int preserve_flag, int resume, int fsync_flag, int inplace_flag) { @@ -2037,7 +2039,7 @@ do_upload(struct sftp_conn *conn, const char *local_path, u_char type, *handle, *data; struct sshbuf *msg; struct stat sb; - Attrib a, t, *c = NULL; + Attrib a, t, c; u_int32_t startid, ackid; u_int64_t highwater = 0, maxack = 0; struct request *ack = NULL; @@ -2073,19 +2075,19 @@ do_upload(struct sftp_conn *conn, const char *local_path, if (resume) { /* Get remote file size if it exists */ - if ((c = do_stat(conn, remote_path, 0)) == NULL) { + if (sftp_stat(conn, remote_path, 0, &c) != 0) { close(local_fd); return -1; } - if ((off_t)c->size >= sb.st_size) { + if ((off_t)c.size >= sb.st_size) { error("resume \"%s\": destination file " "same size or larger", local_path); close(local_fd); return -1; } - if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { + if (lseek(local_fd, (off_t)c.size, SEEK_SET) == -1) { close(local_fd); return -1; } @@ -2109,7 +2111,7 @@ do_upload(struct sftp_conn *conn, const char *local_path, data = xmalloc(conn->upload_buflen); /* Read from local and write to remote */ - offset = progress_counter = (resume ? c->size : 0); + offset = progress_counter = (resume ? c.size : 0); if (showprogress) { start_progress_meter(progress_meter_path(local_path), sb.st_size, &progress_counter); @@ -2221,7 +2223,7 @@ do_upload(struct sftp_conn *conn, const char *local_path, attrib_clear(&t); t.flags = SSH2_FILEXFER_ATTR_SIZE; t.size = highwater; - do_fsetstat(conn, handle, handle_len, &t); + sftp_fsetstat(conn, handle, handle_len, &t); } if (close(local_fd) == -1) { @@ -2231,12 +2233,12 @@ do_upload(struct sftp_conn *conn, const char *local_path, /* Override umask and utimes if asked */ if (preserve_flag) - do_fsetstat(conn, handle, handle_len, &a); + sftp_fsetstat(conn, handle, handle_len, &a); if (fsync_flag) - (void)do_fsync(conn, handle, handle_len); + (void)sftp_fsync(conn, handle, handle_len); - if (do_close(conn, handle, handle_len) != 0) + if (sftp_close(conn, handle, handle_len) != 0) status = SSH2_FX_FAILURE; free(handle); @@ -2254,7 +2256,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, struct dirent *dp; char *filename, *new_src = NULL, *new_dst = NULL; struct stat sb; - Attrib a, *dirattrib; + Attrib a, dirattrib; u_int32_t saved_perm; debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst); @@ -2290,10 +2292,10 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, */ saved_perm = a.perm; a.perm |= (S_IWUSR|S_IXUSR); - if (do_mkdir(conn, dst, &a, 0) != 0) { - if ((dirattrib = do_stat(conn, dst, 0)) == NULL) + if (sftp_mkdir(conn, dst, &a, 0) != 0) { + if (sftp_stat(conn, dst, 0, &dirattrib) != 0) return -1; - if (!S_ISDIR(dirattrib->perm)) { + if (!S_ISDIR(dirattrib.perm)) { error("\"%s\" exists but is not a directory", dst); return -1; } @@ -2311,8 +2313,8 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, free(new_dst); free(new_src); filename = dp->d_name; - new_dst = path_append(dst, filename); - new_src = path_append(src, filename); + new_dst = sftp_path_append(dst, filename); + new_src = sftp_path_append(src, filename); if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) continue; @@ -2341,7 +2343,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, fsync_flag, follow_link_flag, inplace_flag) == -1) ret = -1; } else if (S_ISREG(sb.st_mode)) { - if (do_upload(conn, new_src, new_dst, + if (sftp_upload(conn, new_src, new_dst, preserve_flag, resume, fsync_flag, inplace_flag) == -1) { error("upload \"%s\" to \"%s\" failed", @@ -2354,21 +2356,21 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, free(new_dst); free(new_src); - do_setstat(conn, dst, &a); + sftp_setstat(conn, dst, &a); (void) closedir(dirp); return ret; } int -upload_dir(struct sftp_conn *conn, const char *src, const char *dst, +sftp_upload_dir(struct sftp_conn *conn, const char *src, const char *dst, int preserve_flag, int print_flag, int resume, int fsync_flag, int follow_link_flag, int inplace_flag) { char *dst_canon; int ret; - if ((dst_canon = do_realpath(conn, dst)) == NULL) { + if ((dst_canon = sftp_realpath(conn, dst)) == NULL) { error("upload \"%s\": path canonicalization failed", dst); return -1; } @@ -2427,13 +2429,13 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous, *write_errorp = status; } /* - * XXX this doesn't do full reply matching like do_upload and + * XXX this doesn't do full reply matching like sftp_upload and * so cannot gracefully truncate terminated uploads at a * high-water mark. ATM the only caller of this function (scp) * doesn't support transfer resumption, so this doesn't matter * a whole lot. * - * To be safe, do_crossload truncates the destination file to + * To be safe, sftp_crossload truncates the destination file to * zero length on upload failure, since we can't trust the * server not to have reordered replies that could have * inserted holes where none existed in the source file. @@ -2448,7 +2450,7 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous, } int -do_crossload(struct sftp_conn *from, struct sftp_conn *to, +sftp_crossload(struct sftp_conn *from, struct sftp_conn *to, const char *from_path, const char *to_path, Attrib *a, int preserve_flag) { @@ -2463,13 +2465,17 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, struct requests requests; struct request *req; u_char type; + Attrib attr; debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path); TAILQ_INIT(&requests); - if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL) - return -1; + if (a == NULL) { + if (sftp_stat(from, from_path, 0, &attr) != 0) + return -1; + a = &attr; + } if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && (!S_ISREG(a->perm))) { @@ -2499,7 +2505,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, if (send_open(to, to_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, &to_handle, &to_handle_len) != 0) { - do_close(from, from_handle, from_handle_len); + sftp_close(from, from_handle, from_handle_len); return -1; } @@ -2649,7 +2655,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, /* Truncate at 0 length on interrupt or error to avoid holes at dest */ if (read_error || write_error || interrupted) { debug("truncating \"%s\" at 0", to_path); - do_close(to, to_handle, to_handle_len); + sftp_close(to, to_handle, to_handle_len); free(to_handle); if (send_open(to, to_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, @@ -2661,17 +2667,17 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, if (read_error) { error("read origin \"%s\": %s", from_path, fx2txt(status)); status = -1; - do_close(from, from_handle, from_handle_len); + sftp_close(from, from_handle, from_handle_len); if (to_handle != NULL) - do_close(to, to_handle, to_handle_len); + sftp_close(to, to_handle, to_handle_len); } else if (write_error) { error("write dest \"%s\": %s", to_path, fx2txt(write_error)); status = SSH2_FX_FAILURE; - do_close(from, from_handle, from_handle_len); + sftp_close(from, from_handle, from_handle_len); if (to_handle != NULL) - do_close(to, to_handle, to_handle_len); + sftp_close(to, to_handle, to_handle_len); } else { - if (do_close(from, from_handle, from_handle_len) != 0 || + if (sftp_close(from, from_handle, from_handle_len) != 0 || interrupted) status = -1; else @@ -2679,8 +2685,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, if (to_handle != NULL) { /* Need to resend utimes after write */ if (preserve_flag) - do_fsetstat(to, to_handle, to_handle_len, a); - do_close(to, to_handle, to_handle_len); + sftp_fsetstat(to, to_handle, to_handle_len, a); + sftp_close(to, to_handle, to_handle_len); } } sshbuf_free(msg); @@ -2700,7 +2706,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, SFTP_DIRENT **dir_entries; char *filename, *new_from_path = NULL, *new_to_path = NULL; mode_t mode = 0777; - Attrib curdir; + Attrib curdir, ldirattrib, newdir; debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path); @@ -2709,10 +2715,12 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, return -1; } - if (dirattrib == NULL && - (dirattrib = do_stat(from, from_path, 1)) == NULL) { - error("stat remote \"%s\" failed", from_path); - return -1; + if (dirattrib == NULL) { + if (sftp_stat(from, from_path, 1, &ldirattrib) != 0) { + error("stat remote \"%s\" failed", from_path); + return -1; + } + dirattrib = &ldirattrib; } if (!S_ISDIR(dirattrib->perm)) { error("\"%s\" is not a directory", from_path); @@ -2740,17 +2748,17 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, * the path already existed and is a directory. Ensure we can * write to the directory we create for the duration of the transfer. */ - if (do_mkdir(to, to_path, &curdir, 0) != 0) { - if ((dirattrib = do_stat(to, to_path, 0)) == NULL) + if (sftp_mkdir(to, to_path, &curdir, 0) != 0) { + if (sftp_stat(to, to_path, 0, &newdir) != 0) return -1; - if (!S_ISDIR(dirattrib->perm)) { + if (!S_ISDIR(newdir.perm)) { error("\"%s\" exists but is not a directory", to_path); return -1; } } curdir.perm = mode; - if (do_readdir(from, from_path, &dir_entries) == -1) { + if (sftp_readdir(from, from_path, &dir_entries) == -1) { error("origin readdir \"%s\" failed", from_path); return -1; } @@ -2760,8 +2768,8 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, free(new_to_path); filename = dir_entries[i]->filename; - new_from_path = path_append(from_path, filename); - new_to_path = path_append(to_path, filename); + new_from_path = sftp_path_append(from_path, filename); + new_to_path = sftp_path_append(to_path, filename); if (S_ISDIR(dir_entries[i]->a.perm)) { if (strcmp(filename, ".") == 0 || @@ -2776,10 +2784,10 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { /* * If this is a symlink then don't send the link's - * Attrib. do_download() will do a FXP_STAT operation + * Attrib. sftp_download() will do a FXP_STAT operation * and get the link target's attributes. */ - if (do_crossload(from, to, new_from_path, new_to_path, + if (sftp_crossload(from, to, new_from_path, new_to_path, S_ISLNK(dir_entries[i]->a.perm) ? NULL : &(dir_entries[i]->a), preserve_flag) == -1) { error("crossload \"%s\" to \"%s\" failed", @@ -2794,22 +2802,22 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, free(new_to_path); free(new_from_path); - do_setstat(to, to_path, &curdir); + sftp_setstat(to, to_path, &curdir); - free_sftp_dirents(dir_entries); + sftp_free_dirents(dir_entries); return ret; } int -crossload_dir(struct sftp_conn *from, struct sftp_conn *to, +sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to, const char *from_path, const char *to_path, Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag) { char *from_path_canon; int ret; - if ((from_path_canon = do_realpath(from, from_path)) == NULL) { + if ((from_path_canon = sftp_realpath(from, from_path)) == NULL) { error("crossload \"%s\": path canonicalization failed", from_path); return -1; @@ -2822,13 +2830,13 @@ crossload_dir(struct sftp_conn *from, struct sftp_conn *to, } int -can_get_users_groups_by_id(struct sftp_conn *conn) +sftp_can_get_users_groups_by_id(struct sftp_conn *conn) { return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0; } int -do_get_users_groups_by_id(struct sftp_conn *conn, +sftp_get_users_groups_by_id(struct sftp_conn *conn, const u_int *uids, u_int nuids, const u_int *gids, u_int ngids, char ***usernamesp, char ***groupnamesp) @@ -2840,7 +2848,7 @@ do_get_users_groups_by_id(struct sftp_conn *conn, int r; *usernamesp = *groupnamesp = NULL; - if (!can_get_users_groups_by_id(conn)) + if (!sftp_can_get_users_groups_by_id(conn)) return SSH_ERR_FEATURE_UNSUPPORTED; if ((msg = sshbuf_new()) == NULL || @@ -2936,7 +2944,7 @@ do_get_users_groups_by_id(struct sftp_conn *conn, } char * -path_append(const char *p1, const char *p2) +sftp_path_append(const char *p1, const char *p2) { char *ret; size_t len = strlen(p1) + strlen(p2) + 2; @@ -2955,13 +2963,13 @@ path_append(const char *p1, const char *p2) * freed and a replacement allocated. Caller must free returned string. */ char * -make_absolute(char *p, const char *pwd) +sftp_make_absolute(char *p, const char *pwd) { char *abs_str; /* Derelativise */ if (p && !path_absolute(p)) { - abs_str = path_append(pwd, p); + abs_str = sftp_path_append(pwd, p); free(p); return(abs_str); } else @@ -2969,34 +2977,22 @@ make_absolute(char *p, const char *pwd) } int -remote_is_dir(struct sftp_conn *conn, const char *path) +sftp_remote_is_dir(struct sftp_conn *conn, const char *path) { - Attrib *a; + Attrib a; /* XXX: report errors? */ - if ((a = do_stat(conn, path, 1)) == NULL) + if (sftp_stat(conn, path, 1, &a) != 0) return(0); - if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) + if (!(a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) return(0); - return(S_ISDIR(a->perm)); + return S_ISDIR(a.perm); } -int -local_is_dir(const char *path) -{ - struct stat sb; - - /* XXX: report errors? */ - if (stat(path, &sb) == -1) - return(0); - - return(S_ISDIR(sb.st_mode)); -} - /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ int -globpath_is_dir(const char *pathname) +sftp_globpath_is_dir(const char *pathname) { size_t l = strlen(pathname); diff --git a/sftp-client.h b/sftp-client.h index d7deab17e..74cdae7dc 100644 --- a/sftp-client.h +++ b/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.38 2022/09/19 10:43:12 djm Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.39 2023/09/08 05:56:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller @@ -70,107 +70,106 @@ struct sftp_limits { * Initialise a SSH filexfer connection. Returns NULL on error or * a pointer to a initialized sftp_conn struct on success. */ -struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t); +struct sftp_conn *sftp_init(int, int, u_int, u_int, u_int64_t); u_int sftp_proto_version(struct sftp_conn *); /* Query server limits */ -int do_limits(struct sftp_conn *, struct sftp_limits *); +int sftp_get_limits(struct sftp_conn *, struct sftp_limits *); /* Close file referred to by 'handle' */ -int do_close(struct sftp_conn *, const u_char *, u_int); +int sftp_close(struct sftp_conn *, const u_char *, u_int); /* Read contents of 'path' to NULL-terminated array 'dir' */ -int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***); +int sftp_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***); -/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ -void free_sftp_dirents(SFTP_DIRENT **); +/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from sftp_readdir) */ +void sftp_free_dirents(SFTP_DIRENT **); /* Delete file 'path' */ -int do_rm(struct sftp_conn *, const char *); +int sftp_rm(struct sftp_conn *, const char *); /* Create directory 'path' */ -int do_mkdir(struct sftp_conn *, const char *, Attrib *, int); +int sftp_mkdir(struct sftp_conn *, const char *, Attrib *, int); /* Remove directory 'path' */ -int do_rmdir(struct sftp_conn *, const char *); +int sftp_rmdir(struct sftp_conn *, const char *); /* Get file attributes of 'path' (follows symlinks) */ -Attrib *do_stat(struct sftp_conn *, const char *, int); +int sftp_stat(struct sftp_conn *, const char *, int, Attrib *); /* Get file attributes of 'path' (does not follow symlinks) */ -Attrib *do_lstat(struct sftp_conn *, const char *, int); +int sftp_lstat(struct sftp_conn *, const char *, int, Attrib *); /* Set file attributes of 'path' */ -int do_setstat(struct sftp_conn *, const char *, Attrib *); +int sftp_setstat(struct sftp_conn *, const char *, Attrib *); /* Set file attributes of open file 'handle' */ -int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); +int sftp_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); /* Set file attributes of 'path', not following symlinks */ -int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); +int sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); /* Canonicalise 'path' - caller must free result */ -char *do_realpath(struct sftp_conn *, const char *); +char *sftp_realpath(struct sftp_conn *, const char *); /* Canonicalisation with tilde expansion (requires server extension) */ -char *do_expand_path(struct sftp_conn *, const char *); +char *sftp_expand_path(struct sftp_conn *, const char *); /* Returns non-zero if server can tilde-expand paths */ -int can_expand_path(struct sftp_conn *); +int sftp_can_expand_path(struct sftp_conn *); /* Get statistics for filesystem hosting file at "path" */ -int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); +int sftp_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); /* Rename 'oldpath' to 'newpath' */ -int do_rename(struct sftp_conn *, const char *, const char *, int); +int sftp_rename(struct sftp_conn *, const char *, const char *, int); /* Copy 'oldpath' to 'newpath' */ -int do_copy(struct sftp_conn *, const char *, const char *); +int sftp_copy(struct sftp_conn *, const char *, const char *); /* Link 'oldpath' to 'newpath' */ -int do_hardlink(struct sftp_conn *, const char *, const char *); +int sftp_hardlink(struct sftp_conn *, const char *, const char *); /* Rename 'oldpath' to 'newpath' */ -int do_symlink(struct sftp_conn *, const char *, const char *); +int sftp_symlink(struct sftp_conn *, const char *, const char *); /* Call fsync() on open file 'handle' */ -int do_fsync(struct sftp_conn *conn, u_char *, u_int); +int sftp_fsync(struct sftp_conn *conn, u_char *, u_int); /* * Download 'remote_path' to 'local_path'. Preserve permissions and times * if 'pflag' is set */ -int do_download(struct sftp_conn *, const char *, const char *, Attrib *, +int sftp_download(struct sftp_conn *, const char *, const char *, Attrib *, int, int, int, int); /* * Recursively download 'remote_directory' to 'local_directory'. Preserve * times if 'pflag' is set */ -int download_dir(struct sftp_conn *, const char *, const char *, Attrib *, +int sftp_download_dir(struct sftp_conn *, const char *, const char *, Attrib *, int, int, int, int, int, int); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times * if 'pflag' is set */ -int do_upload(struct sftp_conn *, const char *, const char *, +int sftp_upload(struct sftp_conn *, const char *, const char *, int, int, int, int); /* * Recursively upload 'local_directory' to 'remote_directory'. Preserve * times if 'pflag' is set */ -int upload_dir(struct sftp_conn *, const char *, const char *, +int sftp_upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, int, int, int); /* * Download a 'from_path' from the 'from' connection and upload it to * to 'to' connection at 'to_path'. */ -int -do_crossload(struct sftp_conn *from, struct sftp_conn *to, +int sftp_crossload(struct sftp_conn *from, struct sftp_conn *to, const char *from_path, const char *to_path, Attrib *a, int preserve_flag); @@ -178,7 +177,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, * Recursively download a directory from 'from_path' from the 'from' * connection and upload it to 'to' connection at 'to_path'. */ -int crossload_dir(struct sftp_conn *from, struct sftp_conn *to, +int sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to, const char *from_path, const char *to_path, Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag); @@ -186,26 +185,23 @@ int crossload_dir(struct sftp_conn *from, struct sftp_conn *to, /* * User/group ID to name translation. */ -int can_get_users_groups_by_id(struct sftp_conn *conn); -int do_get_users_groups_by_id(struct sftp_conn *conn, +int sftp_can_get_users_groups_by_id(struct sftp_conn *conn); +int sftp_get_users_groups_by_id(struct sftp_conn *conn, const u_int *uids, u_int nuids, const u_int *gids, u_int ngids, char ***usernamesp, char ***groupnamesp); /* Concatenate paths, taking care of slashes. Caller must free result. */ -char *path_append(const char *, const char *); +char *sftp_path_append(const char *, const char *); /* Make absolute path if relative path and CWD is given. Does not modify * original if the path is already absolute. */ -char *make_absolute(char *, const char *); +char *sftp_make_absolute(char *, const char *); /* Check if remote path is directory */ -int remote_is_dir(struct sftp_conn *conn, const char *path); - -/* Check if local path is directory */ -int local_is_dir(const char *path); +int sftp_remote_is_dir(struct sftp_conn *conn, const char *path); /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ -int globpath_is_dir(const char *pathname); +int sftp_globpath_is_dir(const char *pathname); #endif diff --git a/sftp-glob.c b/sftp-glob.c index afeb15f9e..616168581 100644 --- a/sftp-glob.c +++ b/sftp-glob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-glob.c,v 1.31 2022/10/24 21:51:55 djm Exp $ */ +/* $OpenBSD: sftp-glob.c,v 1.32 2023/09/08 05:56:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -51,7 +51,7 @@ fudge_opendir(const char *path) r = xcalloc(1, sizeof(*r)); - if (do_readdir(cur.conn, path, &r->dir)) { + if (sftp_readdir(cur.conn, path, &r->dir)) { free(r); return(NULL); } @@ -103,32 +103,32 @@ fudge_readdir(struct SFTP_OPENDIR *od) static void fudge_closedir(struct SFTP_OPENDIR *od) { - free_sftp_dirents(od->dir); + sftp_free_dirents(od->dir); free(od); } static int fudge_lstat(const char *path, struct stat *st) { - Attrib *a; + Attrib a; - if (!(a = do_lstat(cur.conn, path, 1))) - return(-1); + if (sftp_lstat(cur.conn, path, 1, &a) != 0) + return -1; - attrib_to_stat(a, st); + attrib_to_stat(&a, st); - return(0); + return 0; } static int fudge_stat(const char *path, struct stat *st) { - Attrib *a; + Attrib a; - if (!(a = do_stat(cur.conn, path, 1))) - return(-1); + if (sftp_stat(cur.conn, path, 1, &a) != 0) + return -1; - attrib_to_stat(a, st); + attrib_to_stat(&a, st); return(0); } diff --git a/sftp-usergroup.c b/sftp-usergroup.c index 083930a4a..93396ffc6 100644 --- a/sftp-usergroup.c +++ b/sftp-usergroup.c @@ -106,9 +106,9 @@ lookup_and_record(struct sftp_conn *conn, u_int i; char **usernames = NULL, **groupnames = NULL; - if ((r = do_get_users_groups_by_id(conn, uids, nuids, gids, ngids, + if ((r = sftp_get_users_groups_by_id(conn, uids, nuids, gids, ngids, &usernames, &groupnames)) != 0) { - debug_fr(r, "do_get_users_groups_by_id"); + debug_fr(r, "sftp_get_users_groups_by_id"); return; } for (i = 0; i < nuids; i++) { @@ -176,7 +176,7 @@ get_remote_user_groups_from_glob(struct sftp_conn *conn, glob_t *g) { u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0; - if (!can_get_users_groups_by_id(conn)) + if (!sftp_can_get_users_groups_by_id(conn)) return; collect_ids_from_glob(g, 1, &uids, &nuids); @@ -215,7 +215,7 @@ get_remote_user_groups_from_dirents(struct sftp_conn *conn, SFTP_DIRENT **d) { u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0; - if (!can_get_users_groups_by_id(conn)) + if (!sftp_can_get_users_groups_by_id(conn)) return; collect_ids_from_dirents(d, 1, &uids, &nuids); diff --git a/sftp.c b/sftp.c index b113f9309..843801c59 100644 --- a/sftp.c +++ b/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.234 2023/04/12 08:53:54 jsg Exp $ */ +/* $OpenBSD: sftp.c,v 1.235 2023/09/08 05:56:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -628,11 +628,21 @@ make_absolute_pwd_glob(char *p, const char *pwd) escpwd = escape_glob(pwd); if (p == NULL) return escpwd; - ret = make_absolute(p, escpwd); + ret = sftp_make_absolute(p, escpwd); free(escpwd); return ret; } +static int +local_is_dir(const char *path) +{ + struct stat sb; + + if (stat(path, &sb) == -1) + return 0; + return S_ISDIR(sb.st_mode); +} + static int process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, int pflag, int rflag, int resume, int fflag) @@ -677,12 +687,12 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst, if (g.gl_matchc == 1 && dst) { if (local_is_dir(dst)) { - abs_dst = path_append(dst, filename); + abs_dst = sftp_path_append(dst, filename); } else { abs_dst = xstrdup(dst); } } else if (dst) { - abs_dst = path_append(dst, filename); + abs_dst = sftp_path_append(dst, filename); } else { abs_dst = xstrdup(filename); } @@ -696,13 +706,14 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst, mprintf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); /* XXX follow link flag */ - if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { - if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, - pflag || global_pflag, 1, resume, + if (sftp_globpath_is_dir(g.gl_pathv[i]) && + (rflag || global_rflag)) { + if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst, + NULL, pflag || global_pflag, 1, resume, fflag || global_fflag, 0, 0) == -1) err = -1; } else { - if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, + if (sftp_download(conn, g.gl_pathv[i], abs_dst, NULL, pflag || global_pflag, resume, fflag || global_fflag, 0) == -1) err = -1; @@ -731,7 +742,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, if (dst) { tmp_dst = xstrdup(dst); - tmp_dst = make_absolute(tmp_dst, pwd); + tmp_dst = sftp_make_absolute(tmp_dst, pwd); } memset(&g, 0, sizeof(g)); @@ -744,7 +755,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, /* If we aren't fetching to pwd then stash this status for later */ if (tmp_dst != NULL) - dst_is_dir = remote_is_dir(conn, tmp_dst); + dst_is_dir = sftp_remote_is_dir(conn, tmp_dst); /* If multiple matches, dst may be directory or unspecified */ if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { @@ -774,13 +785,13 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, if (g.gl_matchc == 1 && tmp_dst) { /* If directory specified, append filename */ if (dst_is_dir) - abs_dst = path_append(tmp_dst, filename); + abs_dst = sftp_path_append(tmp_dst, filename); else abs_dst = xstrdup(tmp_dst); } else if (tmp_dst) { - abs_dst = path_append(tmp_dst, filename); + abs_dst = sftp_path_append(tmp_dst, filename); } else { - abs_dst = make_absolute(xstrdup(filename), pwd); + abs_dst = sftp_make_absolute(xstrdup(filename), pwd); } free(tmp); @@ -792,13 +803,14 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, mprintf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); /* XXX follow_link_flag */ - if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { - if (upload_dir(conn, g.gl_pathv[i], abs_dst, + if (sftp_globpath_is_dir(g.gl_pathv[i]) && + (rflag || global_rflag)) { + if (sftp_upload_dir(conn, g.gl_pathv[i], abs_dst, pflag || global_pflag, 1, resume, fflag || global_fflag, 0, 0) == -1) err = -1; } else { - if (do_upload(conn, g.gl_pathv[i], abs_dst, + if (sftp_upload(conn, g.gl_pathv[i], abs_dst, pflag || global_pflag, resume, fflag || global_fflag, 0) == -1) err = -1; @@ -839,7 +851,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path, u_int c = 1, colspace = 0, columns = 1; SFTP_DIRENT **d; - if ((n = do_readdir(conn, path, &d)) != 0) + if ((n = sftp_readdir(conn, path, &d)) != 0) return (n); if (!(lflag & LS_SHORT_VIEW)) { @@ -881,13 +893,13 @@ do_ls_dir(struct sftp_conn *conn, const char *path, if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) continue; - tmp = path_append(path, d[n]->filename); + tmp = sftp_path_append(path, d[n]->filename); fname = path_strip(tmp, strip_path); free(tmp); if (lflag & LS_LONG_VIEW) { if ((lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) != 0 || - can_get_users_groups_by_id(conn)) { + sftp_can_get_users_groups_by_id(conn)) { char *lname; struct stat sb; @@ -916,7 +928,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path, if (!(lflag & LS_LONG_VIEW) && (c != 1)) printf("\n"); - free_sftp_dirents(d); + sftp_free_dirents(d); return (0); } @@ -1070,7 +1082,7 @@ do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag) char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE]; char s_icapacity[16], s_dcapacity[16]; - if (do_statvfs(conn, path, &st, 1) == -1) + if (sftp_statvfs(conn, path, &st, 1) == -1) return -1; if (st.f_files == 0) strlcpy(s_icapacity, "ERR", sizeof(s_icapacity)); @@ -1544,7 +1556,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, int lflag = 0, pflag = 0, rflag = 0, sflag = 0; int cmdnum, i; unsigned long n_arg = 0; - Attrib a, *aa; + Attrib a, aa; char path_buf[PATH_MAX]; int err = 0; glob_t g; @@ -1585,23 +1597,24 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, rflag, aflag, fflag); break; case I_COPY: - path1 = make_absolute(path1, *pwd); - path2 = make_absolute(path2, *pwd); - err = do_copy(conn, path1, path2); + path1 = sftp_make_absolute(path1, *pwd); + path2 = sftp_make_absolute(path2, *pwd); + err = sftp_copy(conn, path1, path2); break; case I_RENAME: - path1 = make_absolute(path1, *pwd); - path2 = make_absolute(path2, *pwd); - err = do_rename(conn, path1, path2, lflag); + path1 = sftp_make_absolute(path1, *pwd); + path2 = sftp_make_absolute(path2, *pwd); + err = sftp_rename(conn, path1, path2, lflag); break; case I_SYMLINK: sflag = 1; /* FALLTHROUGH */ case I_LINK: if (!sflag) - path1 = make_absolute(path1, *pwd); - path2 = make_absolute(path2, *pwd); - err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); + path1 = sftp_make_absolute(path1, *pwd); + path2 = sftp_make_absolute(path2, *pwd); + err = (sflag ? sftp_symlink : sftp_hardlink)(conn, + path1, path2); break; case I_RM: path1 = make_absolute_pwd_glob(path1, *pwd); @@ -1609,42 +1622,42 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, for (i = 0; g.gl_pathv[i] && !interrupted; i++) { if (!quiet) mprintf("Removing %s\n", g.gl_pathv[i]); - err = do_rm(conn, g.gl_pathv[i]); + err = sftp_rm(conn, g.gl_pathv[i]); if (err != 0 && err_abort) break; } break; case I_MKDIR: - path1 = make_absolute(path1, *pwd); + path1 = sftp_make_absolute(path1, *pwd); attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; - err = do_mkdir(conn, path1, &a, 1); + err = sftp_mkdir(conn, path1, &a, 1); break; case I_RMDIR: - path1 = make_absolute(path1, *pwd); - err = do_rmdir(conn, path1); + path1 = sftp_make_absolute(path1, *pwd); + err = sftp_rmdir(conn, path1); break; case I_CHDIR: if (path1 == NULL || *path1 == '\0') path1 = xstrdup(startdir); - path1 = make_absolute(path1, *pwd); - if ((tmp = do_realpath(conn, path1)) == NULL) { + path1 = sftp_make_absolute(path1, *pwd); + if ((tmp = sftp_realpath(conn, path1)) == NULL) { err = 1; break; } - if ((aa = do_stat(conn, tmp, 0)) == NULL) { + if (sftp_stat(conn, tmp, 0, &aa) != 0) { free(tmp); err = 1; break; } - if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { + if (!(aa.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { error("Can't change directory: Can't check target"); free(tmp); err = 1; break; } - if (!S_ISDIR(aa->perm)) { + if (!S_ISDIR(aa.perm)) { error("Can't change directory: \"%s\" is not " "a directory", tmp); free(tmp); @@ -1672,7 +1685,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, /* Default to current directory if no path specified */ if (path1 == NULL) path1 = xstrdup(*pwd); - path1 = make_absolute(path1, *pwd); + path1 = sftp_make_absolute(path1, *pwd); err = do_df(conn, path1, hflag, iflag); break; case I_LCHDIR: @@ -1714,7 +1727,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, if (!quiet) mprintf("Changing mode on %s\n", g.gl_pathv[i]); - err = (hflag ? do_lsetstat : do_setstat)(conn, + err = (hflag ? sftp_lsetstat : sftp_setstat)(conn, g.gl_pathv[i], &a); if (err != 0 && err_abort) break; @@ -1725,15 +1738,15 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, path1 = make_absolute_pwd_glob(path1, *pwd); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); for (i = 0; g.gl_pathv[i] && !interrupted; i++) { - if (!(aa = (hflag ? do_lstat : do_stat)(conn, - g.gl_pathv[i], 0))) { + if ((hflag ? sftp_lstat : sftp_stat)(conn, + g.gl_pathv[i], 0, &aa) != 0) { if (err_abort) { err = -1; break; } else continue; } - if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { + if (!(aa.flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", g.gl_pathv[i]); if (err_abort) { @@ -1742,20 +1755,20 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, } else continue; } - aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; + aa.flags &= SSH2_FILEXFER_ATTR_UIDGID; if (cmdnum == I_CHOWN) { if (!quiet) mprintf("Changing owner on %s\n", g.gl_pathv[i]); - aa->uid = n_arg; + aa.uid = n_arg; } else { if (!quiet) mprintf("Changing group on %s\n", g.gl_pathv[i]); - aa->gid = n_arg; + aa.gid = n_arg; } - err = (hflag ? do_lsetstat : do_setstat)(conn, - g.gl_pathv[i], aa); + err = (hflag ? sftp_lsetstat : sftp_setstat)(conn, + g.gl_pathv[i], &aa); if (err != 0 && err_abort) break; } @@ -2234,16 +2247,15 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) } #endif /* USE_LIBEDIT */ - remote_path = do_realpath(conn, "."); - if (remote_path == NULL) + if ((remote_path = sftp_realpath(conn, ".")) == NULL) fatal("Need cwd"); startdir = xstrdup(remote_path); if (file1 != NULL) { dir = xstrdup(file1); - dir = make_absolute(dir, remote_path); + dir = sftp_make_absolute(dir, remote_path); - if (remote_is_dir(conn, dir) && file2 == NULL) { + if (sftp_remote_is_dir(conn, dir) && file2 == NULL) { if (!quiet) mprintf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); @@ -2652,7 +2664,7 @@ main(int argc, char **argv) } freeargs(&args); - conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); + conn = sftp_init(in, out, copy_buffer_len, num_requests, limit_kbps); if (conn == NULL) fatal("Couldn't initialise connection to server");