diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2021-08-07 00:12:10 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2021-08-07 00:12:10 +0000 |
commit | acdcf31cdd76553d7ee8dd25282815738b279ab6 (patch) | |
tree | 028205b62601bf19f6026f700f8dd01460941155 /usr.bin/ssh | |
parent | 45cf9b23f72d035217835d5d5a7a252bbcde83da (diff) |
make scp(1) in SFTP mode follow symlinks like traditional scp(1)
ok markus@
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r-- | usr.bin/ssh/scp.c | 8 | ||||
-rw-r--r-- | usr.bin/ssh/sftp-client.c | 58 | ||||
-rw-r--r-- | usr.bin/ssh/sftp-client.h | 9 | ||||
-rw-r--r-- | usr.bin/ssh/sftp.c | 8 |
4 files changed, 53 insertions, 30 deletions
diff --git a/usr.bin/ssh/scp.c b/usr.bin/ssh/scp.c index 7aa6cdbb41e..04c7576accf 100644 --- a/usr.bin/ssh/scp.c +++ b/usr.bin/ssh/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.220 2021/08/07 00:08:52 djm Exp $ */ +/* $OpenBSD: scp.c,v 1.221 2021/08/07 00:12:09 djm Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -1257,7 +1257,7 @@ source_sftp(int argc, char *src, char *targ, if (local_is_dir(src) && iamrecursive) { if (upload_dir(conn, src, abs_dst, pflag, - SFTP_PROGRESS_ONLY, 0, 0) != 0) { + SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) { fatal("failed to upload directory %s to %s", src, abs_dst); } @@ -1489,7 +1489,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn) 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) + pflag, SFTP_PROGRESS_ONLY, 0, 0, 1) == -1) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, @@ -1894,7 +1894,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to, 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, - NULL, pflag, 1) == -1) + NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1) err = -1; } else { if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL, diff --git a/usr.bin/ssh/sftp-client.c b/usr.bin/ssh/sftp-client.c index 06e1d6db247..8a075aee308 100644 --- a/usr.bin/ssh/sftp-client.c +++ b/usr.bin/ssh/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.149 2021/08/07 00:10:49 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.150 2021/08/07 00:12:09 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * @@ -1597,7 +1597,7 @@ do_download(struct sftp_conn *conn, const char *remote_path, static int download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int depth, Attrib *dirattrib, int preserve_flag, int print_flag, - int resume_flag, int fsync_flag) + int resume_flag, int fsync_flag, int follow_link_flag) { int i, ret = 0; SFTP_DIRENT **dir_entries; @@ -1653,12 +1653,20 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, continue; if (download_dir_internal(conn, new_src, new_dst, depth + 1, &(dir_entries[i]->a), preserve_flag, - print_flag, resume_flag, fsync_flag) == -1) + print_flag, resume_flag, + fsync_flag, follow_link_flag) == -1) ret = -1; - } else if (S_ISREG(dir_entries[i]->a.perm) ) { + } else if (S_ISREG(dir_entries[i]->a.perm) || + (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 + * and get the link target's attributes. + */ if (do_download(conn, new_src, new_dst, - &(dir_entries[i]->a), preserve_flag, - resume_flag, fsync_flag) == -1) { + S_ISLNK(dir_entries[i]->a.perm) ? NULL : + &(dir_entries[i]->a), + preserve_flag, resume_flag, fsync_flag) == -1) { error("Download of file %s to %s failed", new_src, new_dst); ret = -1; @@ -1696,7 +1704,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int 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 fsync_flag, int follow_link_flag) { char *src_canon; int ret; @@ -1707,7 +1715,8 @@ download_dir(struct sftp_conn *conn, const char *src, const char *dst, } ret = download_dir_internal(conn, src_canon, dst, 0, - dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag); + dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, + follow_link_flag); free(src_canon); return ret; } @@ -1917,7 +1926,8 @@ do_upload(struct sftp_conn *conn, const char *local_path, static int upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, - int depth, int preserve_flag, int print_flag, int resume, int fsync_flag) + int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, + int follow_link_flag) { int ret = 0; DIR *dirp; @@ -1995,9 +2005,10 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, if (upload_dir_internal(conn, new_src, new_dst, depth + 1, preserve_flag, print_flag, resume, - fsync_flag) == -1) + fsync_flag, follow_link_flag) == -1) ret = -1; - } else if (S_ISREG(sb.st_mode)) { + } else if (S_ISREG(sb.st_mode) || + (follow_link_flag && S_ISLNK(sb.st_mode))) { if (do_upload(conn, new_src, new_dst, preserve_flag, resume, fsync_flag) == -1) { error("Uploading of file %s to %s failed!", @@ -2018,7 +2029,8 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int upload_dir(struct sftp_conn *conn, const char *src, const char *dst, - int preserve_flag, int print_flag, int resume, int fsync_flag) + int preserve_flag, int print_flag, int resume, int fsync_flag, + int follow_link_flag) { char *dst_canon; int ret; @@ -2029,7 +2041,7 @@ upload_dir(struct sftp_conn *conn, const char *src, const char *dst, } ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, - print_flag, resume, fsync_flag); + print_flag, resume, fsync_flag, follow_link_flag); free(dst_canon); return ret; @@ -2353,7 +2365,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, static int crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, const char *from_path, const char *to_path, - int depth, Attrib *dirattrib, int preserve_flag, int print_flag) + int depth, Attrib *dirattrib, int preserve_flag, int print_flag, + int follow_link_flag) { int i, ret = 0; SFTP_DIRENT **dir_entries; @@ -2375,7 +2388,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, error("\"%s\" is not a directory", from_path); return -1; } - if (print_flag) + if (print_flag && print_flag != SFTP_PROGRESS_ONLY) mprintf("Retrieving %s\n", from_path); curdir = *dirattrib; /* dirattrib will be clobbered */ @@ -2427,10 +2440,17 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, if (crossload_dir_internal(from, to, new_from_path, new_to_path, depth + 1, &(dir_entries[i]->a), preserve_flag, - print_flag) == -1) + print_flag, follow_link_flag) == -1) ret = -1; - } else if (S_ISREG(dir_entries[i]->a.perm) ) { + } else if (S_ISREG(dir_entries[i]->a.perm) || + (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 + * and get the link target's attributes. + */ if (do_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("Transfer of file %s to %s failed", new_from_path, new_to_path); @@ -2453,7 +2473,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to, int 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) + Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag) { char *from_path_canon; int ret; @@ -2464,7 +2484,7 @@ crossload_dir(struct sftp_conn *from, struct sftp_conn *to, } ret = crossload_dir_internal(from, to, from_path_canon, to_path, 0, - dirattrib, preserve_flag, print_flag); + dirattrib, preserve_flag, print_flag, follow_link_flag); free(from_path_canon); return ret; } diff --git a/usr.bin/ssh/sftp-client.h b/usr.bin/ssh/sftp-client.h index 03fe96b10c8..349094b4568 100644 --- a/usr.bin/ssh/sftp-client.h +++ b/usr.bin/ssh/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.32 2021/08/07 00:08:52 djm Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.33 2021/08/07 00:12:09 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> @@ -134,7 +134,7 @@ int do_download(struct sftp_conn *, const char *, const char *, * times if 'pflag' is set */ int download_dir(struct sftp_conn *, const char *, const char *, - Attrib *, int, int, int, int); + Attrib *, int, int, int, int, int); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times @@ -147,7 +147,7 @@ int do_upload(struct sftp_conn *, const char *, const char *, int, int, int); * times if 'pflag' is set */ int 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 @@ -164,7 +164,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to, */ int 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); + Attrib *dirattrib, int preserve_flag, int print_flag, + int follow_link_flag); /* Concatenate paths, taking care of slashes. Caller must free result. */ char *path_append(const char *, const char *); diff --git a/usr.bin/ssh/sftp.c b/usr.bin/ssh/sftp.c index 69ba7ae7bb1..7a82302858f 100644 --- a/usr.bin/ssh/sftp.c +++ b/usr.bin/ssh/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.209 2021/04/03 06:58:30 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.210 2021/08/07 00:12:09 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * @@ -633,10 +633,11 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst, else if (!quiet && !resume) 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, - fflag || global_fflag) == -1) + fflag || global_fflag, 0) == -1) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, @@ -726,10 +727,11 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, else if (!quiet && !resume) 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, pflag || global_pflag, 1, resume, - fflag || global_fflag) == -1) + fflag || global_fflag, 0) == -1) err = -1; } else { if (do_upload(conn, g.gl_pathv[i], abs_dst, |