View | Details | Raw Unified | Return to bug 430 | Differences between
and this patch

Collapse All | Expand All

(-)sftp-server.c (-10 / +117 lines)
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);

Return to bug 430