|
Lines 38-43
Link Here
|
| 38 |
/* Version of client */ |
38 |
/* Version of client */ |
| 39 |
int version; |
39 |
int version; |
| 40 |
|
40 |
|
|
|
41 |
/* Path restrictions */ |
| 42 |
|
| 43 |
/* Path, relative to user home directory, to jail users in */ |
| 44 |
char *restrict_path = NULL; |
| 45 |
|
| 46 |
int |
| 47 |
check_path_restrict(const char *try_path) |
| 48 |
{ |
| 49 |
struct passwd *pw; |
| 50 |
size_t len; |
| 51 |
int i; |
| 52 |
char rpath[PATH_MAX], tmp[PATH_MAX]; |
| 53 |
|
| 54 |
if (restrict_path == NULL) |
| 55 |
return (0); |
| 56 |
|
| 57 |
if (strlen(try_path) == 0) |
| 58 |
return (-1); |
| 59 |
if ((pw = getpwuid(getuid())) == NULL) |
| 60 |
return (-1); |
| 61 |
if (pw->pw_dir == NULL || strlen(pw->pw_dir) == 0) |
| 62 |
return (-1); |
| 63 |
if (strlcpy(tmp, pw->pw_dir, sizeof(tmp)) >= sizeof(tmp)) |
| 64 |
return (-1); |
| 65 |
if (strlcat(tmp, "/", sizeof(tmp)) >= sizeof(tmp)) |
| 66 |
return (-1); |
| 67 |
if (strlcat(tmp, restrict_path, sizeof(tmp)) >= sizeof(tmp)) |
| 68 |
return (-1); |
| 69 |
if (realpath(tmp, rpath) == NULL) |
| 70 |
return (-1); |
| 71 |
if (realpath(try_path, tmp) == NULL) { |
| 72 |
if (errno != ENOENT) |
| 73 |
return (-1); |
| 74 |
|
| 75 |
strlcpy(tmp, try_path, sizeof(tmp)); |
| 76 |
len = strlen(tmp); |
| 77 |
for (i = 0; i < len; i++) { |
| 78 |
if (tmp[i] == '.' && tmp[i + 1] == '.' && |
| 79 |
(i == 0 || tmp[i - 1] == '/') && |
| 80 |
(tmp[i + 2] == '/' || tmp[i + 2] == '\0')) |
| 81 |
return (-1); |
| 82 |
} |
| 83 |
} |
| 84 |
if ((len = strlen(rpath)) == 0) |
| 85 |
return (-1); |
| 86 |
if (strncmp(rpath, tmp, len) != 0) |
| 87 |
return (-1); |
| 88 |
return (0); |
| 89 |
} |
| 90 |
|
| 41 |
/* portable attributes, etc. */ |
91 |
/* portable attributes, etc. */ |
| 42 |
|
92 |
|
| 43 |
typedef struct Stat Stat; |
93 |
typedef struct Stat Stat; |
|
Lines 380-386
Link Here
|
| 380 |
flags = flags_from_portable(pflags); |
430 |
flags = flags_from_portable(pflags); |
| 381 |
mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; |
431 |
mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; |
| 382 |
TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); |
432 |
TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); |
| 383 |
fd = open(name, flags, mode); |
433 |
if (check_path_restrict(name) == -1) { |
|
|
434 |
errno = EPERM; |
| 435 |
fd = -1; |
| 436 |
} else |
| 437 |
fd = open(name, flags, mode); |
| 438 |
|
| 384 |
if (fd < 0) { |
439 |
if (fd < 0) { |
| 385 |
status = errno_to_portable(errno); |
440 |
status = errno_to_portable(errno); |
| 386 |
} else { |
441 |
} else { |
|
Lines 501-507
Link Here
|
| 501 |
id = get_int(); |
556 |
id = get_int(); |
| 502 |
name = get_string(NULL); |
557 |
name = get_string(NULL); |
| 503 |
TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); |
558 |
TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); |
| 504 |
ret = do_lstat ? lstat(name, &st) : stat(name, &st); |
559 |
if (check_path_restrict(name) == -1) { |
|
|
560 |
errno = EPERM; |
| 561 |
ret = -1; |
| 562 |
} else |
| 563 |
ret = do_lstat ? lstat(name, &st) : stat(name, &st); |
| 505 |
if (ret < 0) { |
564 |
if (ret < 0) { |
| 506 |
status = errno_to_portable(errno); |
565 |
status = errno_to_portable(errno); |
| 507 |
} else { |
566 |
} else { |
|
Lines 575-580
Link Here
|
| 575 |
id = get_int(); |
634 |
id = get_int(); |
| 576 |
name = get_string(NULL); |
635 |
name = get_string(NULL); |
| 577 |
a = get_attrib(); |
636 |
a = get_attrib(); |
|
|
637 |
if (check_path_restrict(name) == -1) { |
| 638 |
status = errno_to_portable(errno); |
| 639 |
ret = -1; |
| 640 |
a->flags = 0; |
| 641 |
} |
| 578 |
TRACE("setstat id %u name %s", id, name); |
642 |
TRACE("setstat id %u name %s", id, name); |
| 579 |
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { |
643 |
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { |
| 580 |
ret = truncate(name, a->size); |
644 |
ret = truncate(name, a->size); |
|
Lines 651-657
Link Here
|
| 651 |
id = get_int(); |
715 |
id = get_int(); |
| 652 |
path = get_string(NULL); |
716 |
path = get_string(NULL); |
| 653 |
TRACE("opendir id %u path %s", id, path); |
717 |
TRACE("opendir id %u path %s", id, path); |
| 654 |
dirp = opendir(path); |
718 |
if (check_path_restrict(path) == -1) { |
|
|
719 |
errno = EPERM; |
| 720 |
dirp = NULL; |
| 721 |
} else |
| 722 |
dirp = opendir(path); |
| 723 |
|
| 655 |
if (dirp == NULL) { |
724 |
if (dirp == NULL) { |
| 656 |
status = errno_to_portable(errno); |
725 |
status = errno_to_portable(errno); |
| 657 |
} else { |
726 |
} else { |
|
Lines 735-741
Link Here
|
| 735 |
id = get_int(); |
804 |
id = get_int(); |
| 736 |
name = get_string(NULL); |
805 |
name = get_string(NULL); |
| 737 |
TRACE("remove id %u name %s", id, name); |
806 |
TRACE("remove id %u name %s", id, name); |
| 738 |
ret = unlink(name); |
807 |
if (check_path_restrict(name) == -1) { |
|
|
808 |
errno = EPERM; |
| 809 |
ret = -1; |
| 810 |
} else |
| 811 |
ret = unlink(name); |
| 739 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
812 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
| 740 |
send_status(id, status); |
813 |
send_status(id, status); |
| 741 |
xfree(name); |
814 |
xfree(name); |
|
Lines 755-761
Link Here
|
| 755 |
mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? |
828 |
mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? |
| 756 |
a->perm & 0777 : 0777; |
829 |
a->perm & 0777 : 0777; |
| 757 |
TRACE("mkdir id %u name %s mode 0%o", id, name, mode); |
830 |
TRACE("mkdir id %u name %s mode 0%o", id, name, mode); |
| 758 |
ret = mkdir(name, mode); |
831 |
if (check_path_restrict(name) == -1) { |
|
|
832 |
errno = EPERM; |
| 833 |
ret = -1; |
| 834 |
} else |
| 835 |
ret = mkdir(name, mode); |
| 759 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
836 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
| 760 |
send_status(id, status); |
837 |
send_status(id, status); |
| 761 |
xfree(name); |
838 |
xfree(name); |
|
Lines 771-777
Link Here
|
| 771 |
id = get_int(); |
848 |
id = get_int(); |
| 772 |
name = get_string(NULL); |
849 |
name = get_string(NULL); |
| 773 |
TRACE("rmdir id %u name %s", id, name); |
850 |
TRACE("rmdir id %u name %s", id, name); |
| 774 |
ret = rmdir(name); |
851 |
if (check_path_restrict(name) == -1) { |
|
|
852 |
errno = EPERM; |
| 853 |
ret = -1; |
| 854 |
} else |
| 855 |
ret = rmdir(name); |
| 775 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
856 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
| 776 |
send_status(id, status); |
857 |
send_status(id, status); |
| 777 |
xfree(name); |
858 |
xfree(name); |
|
Lines 791-797
Link Here
|
| 791 |
path = xstrdup("."); |
872 |
path = xstrdup("."); |
| 792 |
} |
873 |
} |
| 793 |
TRACE("realpath id %u path %s", id, path); |
874 |
TRACE("realpath id %u path %s", id, path); |
| 794 |
if (realpath(path, resolvedname) == NULL) { |
875 |
if (check_path_restrict(path) == -1) { |
|
|
876 |
send_status(id, errno_to_portable(EPERM)); |
| 877 |
} else if (realpath(path, resolvedname) == NULL) { |
| 795 |
send_status(id, errno_to_portable(errno)); |
878 |
send_status(id, errno_to_portable(errno)); |
| 796 |
} else { |
879 |
} else { |
| 797 |
Stat s; |
880 |
Stat s; |
|
Lines 815-821
Link Here
|
| 815 |
newpath = get_string(NULL); |
898 |
newpath = get_string(NULL); |
| 816 |
TRACE("rename id %u old %s new %s", id, oldpath, newpath); |
899 |
TRACE("rename id %u old %s new %s", id, oldpath, newpath); |
| 817 |
status = SSH2_FX_FAILURE; |
900 |
status = SSH2_FX_FAILURE; |
| 818 |
if (lstat(oldpath, &sb) == -1) |
901 |
errno = EPERM; |
|
|
902 |
if (check_path_restrict(oldpath) == -1 || |
| 903 |
check_path_restrict(newpath) == -1 || |
| 904 |
lstat(oldpath, &sb) == -1) |
| 819 |
status = errno_to_portable(errno); |
905 |
status = errno_to_portable(errno); |
| 820 |
else if (S_ISREG(sb.st_mode)) { |
906 |
else if (S_ISREG(sb.st_mode)) { |
| 821 |
/* Race-free rename of regular files */ |
907 |
/* Race-free rename of regular files */ |
|
Lines 849-855
Link Here
|
| 849 |
id = get_int(); |
935 |
id = get_int(); |
| 850 |
path = get_string(NULL); |
936 |
path = get_string(NULL); |
| 851 |
TRACE("readlink id %u path %s", id, path); |
937 |
TRACE("readlink id %u path %s", id, path); |
| 852 |
if ((len = readlink(path, link, sizeof(link) - 1)) == -1) |
938 |
errno = EPERM; |
|
|
939 |
if (check_path_restrict(path) == -1 || |
| 940 |
(len = readlink(path, link, sizeof(link) - 1)) == -1) |
| 853 |
send_status(id, errno_to_portable(errno)); |
941 |
send_status(id, errno_to_portable(errno)); |
| 854 |
else { |
942 |
else { |
| 855 |
Stat s; |
943 |
Stat s; |
|
Lines 874-880
Link Here
|
| 874 |
newpath = get_string(NULL); |
962 |
newpath = get_string(NULL); |
| 875 |
TRACE("symlink id %u old %s new %s", id, oldpath, newpath); |
963 |
TRACE("symlink id %u old %s new %s", id, oldpath, newpath); |
| 876 |
/* this will fail if 'newpath' exists */ |
964 |
/* this will fail if 'newpath' exists */ |
| 877 |
ret = symlink(oldpath, newpath); |
965 |
if (check_path_restrict(oldpath) == -1 || |
|
|
966 |
check_path_restrict(newpath) == -1) { |
| 967 |
ret = -1; |
| 968 |
errno = EPERM; |
| 969 |
} else |
| 970 |
ret = symlink(oldpath, newpath); |
| 878 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
971 |
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; |
| 879 |
send_status(id, status); |
972 |
send_status(id, status); |
| 880 |
xfree(oldpath); |
973 |
xfree(oldpath); |
|
Lines 1003-1008
Link Here
|
| 1003 |
/* XXX should use getopt */ |
1096 |
/* XXX should use getopt */ |
| 1004 |
|
1097 |
|
| 1005 |
handle_init(); |
1098 |
handle_init(); |
|
|
1099 |
|
| 1100 |
if (ac > 1) { |
| 1101 |
struct passwd *pw; |
| 1102 |
|
| 1103 |
restrict_path = av[1]; |
| 1104 |
if ((pw = getpwuid(getuid())) == NULL) |
| 1105 |
exit(1); |
| 1106 |
if (pw->pw_dir == NULL || strlen(pw->pw_dir) == 0) |
| 1107 |
exit(1); |
| 1108 |
if (chdir(pw->pw_dir) == -1) |
| 1109 |
exit(1); |
| 1110 |
if (chdir(restrict_path) == -1) |
| 1111 |
exit(1); |
| 1112 |
} |
| 1006 |
|
1113 |
|
| 1007 |
#ifdef DEBUG_SFTP_SERVER |
1114 |
#ifdef DEBUG_SFTP_SERVER |
| 1008 |
log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); |
1115 |
log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); |