diff options
Diffstat (limited to 'sftp-server.c')
-rw-r--r-- | sftp-server.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/sftp-server.c b/sftp-server.c index 84264693d..9a66b4de7 100644 --- a/sftp-server.c +++ b/sftp-server.c | |||
@@ -22,7 +22,7 @@ | |||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ | 23 | */ |
24 | #include "includes.h" | 24 | #include "includes.h" |
25 | RCSID("$OpenBSD: sftp-server.c,v 1.38 2002/09/11 22:41:50 djm Exp $"); | 25 | RCSID("$OpenBSD: sftp-server.c,v 1.41 2003/03/26 04:02:51 deraadt Exp $"); |
26 | 26 | ||
27 | #include "buffer.h" | 27 | #include "buffer.h" |
28 | #include "bufaux.h" | 28 | #include "bufaux.h" |
@@ -158,7 +158,7 @@ handle_new(int use, char *name, int fd, DIR *dirp) | |||
158 | handles[i].use = use; | 158 | handles[i].use = use; |
159 | handles[i].dirp = dirp; | 159 | handles[i].dirp = dirp; |
160 | handles[i].fd = fd; | 160 | handles[i].fd = fd; |
161 | handles[i].name = name; | 161 | handles[i].name = xstrdup(name); |
162 | return i; | 162 | return i; |
163 | } | 163 | } |
164 | } | 164 | } |
@@ -230,9 +230,11 @@ handle_close(int handle) | |||
230 | if (handle_is_ok(handle, HANDLE_FILE)) { | 230 | if (handle_is_ok(handle, HANDLE_FILE)) { |
231 | ret = close(handles[handle].fd); | 231 | ret = close(handles[handle].fd); |
232 | handles[handle].use = HANDLE_UNUSED; | 232 | handles[handle].use = HANDLE_UNUSED; |
233 | xfree(handles[handle].name); | ||
233 | } else if (handle_is_ok(handle, HANDLE_DIR)) { | 234 | } else if (handle_is_ok(handle, HANDLE_DIR)) { |
234 | ret = closedir(handles[handle].dirp); | 235 | ret = closedir(handles[handle].dirp); |
235 | handles[handle].use = HANDLE_UNUSED; | 236 | handles[handle].use = HANDLE_UNUSED; |
237 | xfree(handles[handle].name); | ||
236 | } else { | 238 | } else { |
237 | errno = ENOENT; | 239 | errno = ENOENT; |
238 | } | 240 | } |
@@ -396,7 +398,7 @@ process_open(void) | |||
396 | if (fd < 0) { | 398 | if (fd < 0) { |
397 | status = errno_to_portable(errno); | 399 | status = errno_to_portable(errno); |
398 | } else { | 400 | } else { |
399 | handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL); | 401 | handle = handle_new(HANDLE_FILE, name, fd, NULL); |
400 | if (handle < 0) { | 402 | if (handle < 0) { |
401 | close(fd); | 403 | close(fd); |
402 | } else { | 404 | } else { |
@@ -681,7 +683,7 @@ process_opendir(void) | |||
681 | if (dirp == NULL) { | 683 | if (dirp == NULL) { |
682 | status = errno_to_portable(errno); | 684 | status = errno_to_portable(errno); |
683 | } else { | 685 | } else { |
684 | handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); | 686 | handle = handle_new(HANDLE_DIR, path, 0, dirp); |
685 | if (handle < 0) { | 687 | if (handle < 0) { |
686 | closedir(dirp); | 688 | closedir(dirp); |
687 | } else { | 689 | } else { |
@@ -832,18 +834,32 @@ static void | |||
832 | process_rename(void) | 834 | process_rename(void) |
833 | { | 835 | { |
834 | u_int32_t id; | 836 | u_int32_t id; |
835 | struct stat st; | ||
836 | char *oldpath, *newpath; | 837 | char *oldpath, *newpath; |
837 | int ret, status = SSH2_FX_FAILURE; | 838 | int status; |
839 | struct stat sb; | ||
838 | 840 | ||
839 | id = get_int(); | 841 | id = get_int(); |
840 | oldpath = get_string(NULL); | 842 | oldpath = get_string(NULL); |
841 | newpath = get_string(NULL); | 843 | newpath = get_string(NULL); |
842 | TRACE("rename id %u old %s new %s", id, oldpath, newpath); | 844 | TRACE("rename id %u old %s new %s", id, oldpath, newpath); |
843 | /* fail if 'newpath' exists */ | 845 | status = SSH2_FX_FAILURE; |
844 | if (stat(newpath, &st) == -1) { | 846 | if (lstat(oldpath, &sb) == -1) |
845 | ret = rename(oldpath, newpath); | 847 | status = errno_to_portable(errno); |
846 | status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; | 848 | else if (S_ISREG(sb.st_mode)) { |
849 | /* Race-free rename of regular files */ | ||
850 | if (link(oldpath, newpath) == -1) | ||
851 | status = errno_to_portable(errno); | ||
852 | else if (unlink(oldpath) == -1) { | ||
853 | status = errno_to_portable(errno); | ||
854 | /* clean spare link */ | ||
855 | unlink(newpath); | ||
856 | } else | ||
857 | status = SSH2_FX_OK; | ||
858 | } else if (stat(newpath, &sb) == -1) { | ||
859 | if (rename(oldpath, newpath) == -1) | ||
860 | status = errno_to_portable(errno); | ||
861 | else | ||
862 | status = SSH2_FX_OK; | ||
847 | } | 863 | } |
848 | send_status(id, status); | 864 | send_status(id, status); |
849 | xfree(oldpath); | 865 | xfree(oldpath); |
@@ -878,19 +894,16 @@ static void | |||
878 | process_symlink(void) | 894 | process_symlink(void) |
879 | { | 895 | { |
880 | u_int32_t id; | 896 | u_int32_t id; |
881 | struct stat st; | ||
882 | char *oldpath, *newpath; | 897 | char *oldpath, *newpath; |
883 | int ret, status = SSH2_FX_FAILURE; | 898 | int ret, status; |
884 | 899 | ||
885 | id = get_int(); | 900 | id = get_int(); |
886 | oldpath = get_string(NULL); | 901 | oldpath = get_string(NULL); |
887 | newpath = get_string(NULL); | 902 | newpath = get_string(NULL); |
888 | TRACE("symlink id %u old %s new %s", id, oldpath, newpath); | 903 | TRACE("symlink id %u old %s new %s", id, oldpath, newpath); |
889 | /* fail if 'newpath' exists */ | 904 | /* this will fail if 'newpath' exists */ |
890 | if (stat(newpath, &st) == -1) { | 905 | ret = symlink(oldpath, newpath); |
891 | ret = symlink(oldpath, newpath); | 906 | status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
892 | status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; | ||
893 | } | ||
894 | send_status(id, status); | 907 | send_status(id, status); |
895 | xfree(oldpath); | 908 | xfree(oldpath); |
896 | xfree(newpath); | 909 | xfree(newpath); |