diff options
author | Damien Miller <djm@mindrot.org> | 2008-02-10 22:40:12 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2008-02-10 22:40:12 +1100 |
commit | d8cb1f184f9acaae02bb4d15ce1e00ffbeeeac88 (patch) | |
tree | fb0100a74a6c870e835706aa487b54500510c5e1 | |
parent | dfc24258a75a06ea8a3f56d99d3669e1a012a1dc (diff) |
- djm@cvs.openbsd.org 2008/02/08 23:24:07
[servconf.c servconf.h session.c sftp-server.c sftp.h sshd_config]
[sshd_config.5]
add sshd_config ChrootDirectory option to chroot(2) users to a directory
and tweak internal sftp server to work with it (no special files in
chroot required). ok markus@
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | servconf.c | 12 | ||||
-rw-r--r-- | servconf.h | 4 | ||||
-rw-r--r-- | session.c | 106 | ||||
-rw-r--r-- | sftp-server-main.c | 50 | ||||
-rw-r--r-- | sftp-server.c | 10 | ||||
-rw-r--r-- | sftp.h | 6 | ||||
-rw-r--r-- | sshd_config | 3 | ||||
-rw-r--r-- | sshd_config.5 | 54 |
9 files changed, 220 insertions, 31 deletions
diff --git a/Makefile.in b/Makefile.in index 2486edc95..1f78ea9cc 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Makefile.in,v 1.285 2007/06/11 04:01:42 djm Exp $ | 1 | # $Id: Makefile.in,v 1.286 2008/02/10 11:40:12 djm Exp $ |
2 | 2 | ||
3 | # uncomment if you run a non bourne compatable shell. Ie. csh | 3 | # uncomment if you run a non bourne compatable shell. Ie. csh |
4 | #SHELL = @SH@ | 4 | #SHELL = @SH@ |
@@ -156,8 +156,8 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o | |||
156 | ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o | 156 | ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o |
157 | $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) | 157 | $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) |
158 | 158 | ||
159 | sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o | 159 | sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o |
160 | $(LD) -o $@ sftp-server.o sftp-common.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | 160 | $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
161 | 161 | ||
162 | sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o | 162 | sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o |
163 | $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) | 163 | $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) |
diff --git a/servconf.c b/servconf.c index 19c286c18..d38d0bfb1 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.c,v 1.175 2008/01/01 09:27:33 dtucker Exp $ */ | 1 | /* $OpenBSD: servconf.c,v 1.176 2008/02/08 23:24:08 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -122,6 +122,7 @@ initialize_server_options(ServerOptions *options) | |||
122 | options->permit_tun = -1; | 122 | options->permit_tun = -1; |
123 | options->num_permitted_opens = -1; | 123 | options->num_permitted_opens = -1; |
124 | options->adm_forced_command = NULL; | 124 | options->adm_forced_command = NULL; |
125 | options->chroot_directory = NULL; | ||
125 | } | 126 | } |
126 | 127 | ||
127 | void | 128 | void |
@@ -291,7 +292,7 @@ typedef enum { | |||
291 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | 292 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, |
292 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, | 293 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, |
293 | sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, | 294 | sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, |
294 | sMatch, sPermitOpen, sForceCommand, | 295 | sMatch, sPermitOpen, sForceCommand, sChrootDirectory, |
295 | sUsePrivilegeSeparation, | 296 | sUsePrivilegeSeparation, |
296 | sDeprecated, sUnsupported | 297 | sDeprecated, sUnsupported |
297 | } ServerOpCodes; | 298 | } ServerOpCodes; |
@@ -403,6 +404,7 @@ static struct { | |||
403 | { "match", sMatch, SSHCFG_ALL }, | 404 | { "match", sMatch, SSHCFG_ALL }, |
404 | { "permitopen", sPermitOpen, SSHCFG_ALL }, | 405 | { "permitopen", sPermitOpen, SSHCFG_ALL }, |
405 | { "forcecommand", sForceCommand, SSHCFG_ALL }, | 406 | { "forcecommand", sForceCommand, SSHCFG_ALL }, |
407 | { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, | ||
406 | { NULL, sBadOption, 0 } | 408 | { NULL, sBadOption, 0 } |
407 | }; | 409 | }; |
408 | 410 | ||
@@ -1147,6 +1149,7 @@ parse_flag: | |||
1147 | case sBanner: | 1149 | case sBanner: |
1148 | charptr = &options->banner; | 1150 | charptr = &options->banner; |
1149 | goto parse_filename; | 1151 | goto parse_filename; |
1152 | |||
1150 | /* | 1153 | /* |
1151 | * These options can contain %X options expanded at | 1154 | * These options can contain %X options expanded at |
1152 | * connect time, so that you can specify paths like: | 1155 | * connect time, so that you can specify paths like: |
@@ -1255,6 +1258,10 @@ parse_flag: | |||
1255 | options->adm_forced_command = xstrdup(cp + len); | 1258 | options->adm_forced_command = xstrdup(cp + len); |
1256 | return 0; | 1259 | return 0; |
1257 | 1260 | ||
1261 | case sChrootDirectory: | ||
1262 | charptr = &options->chroot_directory; | ||
1263 | goto parse_filename; | ||
1264 | |||
1258 | case sDeprecated: | 1265 | case sDeprecated: |
1259 | logit("%s line %d: Deprecated option %s", | 1266 | logit("%s line %d: Deprecated option %s", |
1260 | filename, linenum, arg); | 1267 | filename, linenum, arg); |
@@ -1363,6 +1370,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
1363 | if (preauth) | 1370 | if (preauth) |
1364 | return; | 1371 | return; |
1365 | M_CP_STROPT(adm_forced_command); | 1372 | M_CP_STROPT(adm_forced_command); |
1373 | M_CP_STROPT(chroot_directory); | ||
1366 | } | 1374 | } |
1367 | 1375 | ||
1368 | #undef M_CP_INTOPT | 1376 | #undef M_CP_INTOPT |
diff --git a/servconf.h b/servconf.h index 8a5b950ea..81a68be89 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.80 2007/02/19 10:45:58 dtucker Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.81 2008/02/08 23:24:08 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -141,6 +141,8 @@ typedef struct { | |||
141 | int permit_tun; | 141 | int permit_tun; |
142 | 142 | ||
143 | int num_permitted_opens; | 143 | int num_permitted_opens; |
144 | |||
145 | char *chroot_directory; | ||
144 | } ServerOptions; | 146 | } ServerOptions; |
145 | 147 | ||
146 | void initialize_server_options(ServerOptions *); | 148 | void initialize_server_options(ServerOptions *); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.c,v 1.225 2008/02/04 21:53:00 markus Exp $ */ | 1 | /* $OpenBSD: session.c,v 1.226 2008/02/08 23:24:07 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -84,6 +84,7 @@ | |||
84 | #include "sshlogin.h" | 84 | #include "sshlogin.h" |
85 | #include "serverloop.h" | 85 | #include "serverloop.h" |
86 | #include "canohost.h" | 86 | #include "canohost.h" |
87 | #include "misc.h" | ||
87 | #include "session.h" | 88 | #include "session.h" |
88 | #include "kex.h" | 89 | #include "kex.h" |
89 | #include "monitor_wrap.h" | 90 | #include "monitor_wrap.h" |
@@ -93,6 +94,9 @@ | |||
93 | #include <kafs.h> | 94 | #include <kafs.h> |
94 | #endif | 95 | #endif |
95 | 96 | ||
97 | /* Magic name for internal sftp-server */ | ||
98 | #define INTERNAL_SFTP_NAME "internal-sftp" | ||
99 | |||
96 | /* func */ | 100 | /* func */ |
97 | 101 | ||
98 | Session *session_new(void); | 102 | Session *session_new(void); |
@@ -130,7 +134,7 @@ extern Buffer loginmsg; | |||
130 | const char *original_command = NULL; | 134 | const char *original_command = NULL; |
131 | 135 | ||
132 | /* data */ | 136 | /* data */ |
133 | #define MAX_SESSIONS 10 | 137 | #define MAX_SESSIONS 20 |
134 | Session sessions[MAX_SESSIONS]; | 138 | Session sessions[MAX_SESSIONS]; |
135 | 139 | ||
136 | #define SUBSYSTEM_NONE 0 | 140 | #define SUBSYSTEM_NONE 0 |
@@ -688,13 +692,17 @@ do_exec(Session *s, const char *command) | |||
688 | if (options.adm_forced_command) { | 692 | if (options.adm_forced_command) { |
689 | original_command = command; | 693 | original_command = command; |
690 | command = options.adm_forced_command; | 694 | command = options.adm_forced_command; |
691 | if (s->is_subsystem) | 695 | if (strcmp(INTERNAL_SFTP_NAME, command) == 0) |
696 | s->is_subsystem = SUBSYSTEM_INT_SFTP; | ||
697 | else if (s->is_subsystem) | ||
692 | s->is_subsystem = SUBSYSTEM_EXT; | 698 | s->is_subsystem = SUBSYSTEM_EXT; |
693 | debug("Forced command (config) '%.900s'", command); | 699 | debug("Forced command (config) '%.900s'", command); |
694 | } else if (forced_command) { | 700 | } else if (forced_command) { |
695 | original_command = command; | 701 | original_command = command; |
696 | command = forced_command; | 702 | command = forced_command; |
697 | if (s->is_subsystem) | 703 | if (strcmp(INTERNAL_SFTP_NAME, command) == 0) |
704 | s->is_subsystem = SUBSYSTEM_INT_SFTP; | ||
705 | else if (s->is_subsystem) | ||
698 | s->is_subsystem = SUBSYSTEM_EXT; | 706 | s->is_subsystem = SUBSYSTEM_EXT; |
699 | debug("Forced command (key option) '%.900s'", command); | 707 | debug("Forced command (key option) '%.900s'", command); |
700 | } | 708 | } |
@@ -710,7 +718,6 @@ do_exec(Session *s, const char *command) | |||
710 | PRIVSEP(audit_run_command(shell)); | 718 | PRIVSEP(audit_run_command(shell)); |
711 | } | 719 | } |
712 | #endif | 720 | #endif |
713 | |||
714 | if (s->ttyfd != -1) | 721 | if (s->ttyfd != -1) |
715 | do_exec_pty(s, command); | 722 | do_exec_pty(s, command); |
716 | else | 723 | else |
@@ -1293,6 +1300,61 @@ do_nologin(struct passwd *pw) | |||
1293 | } | 1300 | } |
1294 | } | 1301 | } |
1295 | 1302 | ||
1303 | /* | ||
1304 | * Chroot into a directory after checking it for safety: all path components | ||
1305 | * must be root-owned directories with strict permissions. | ||
1306 | */ | ||
1307 | static void | ||
1308 | safely_chroot(const char *path, uid_t uid) | ||
1309 | { | ||
1310 | const char *cp; | ||
1311 | char component[MAXPATHLEN]; | ||
1312 | struct stat st; | ||
1313 | |||
1314 | if (*path != '/') | ||
1315 | fatal("chroot path does not begin at root"); | ||
1316 | if (strlen(path) >= sizeof(component)) | ||
1317 | fatal("chroot path too long"); | ||
1318 | |||
1319 | /* | ||
1320 | * Descend the path, checking that each component is a | ||
1321 | * root-owned directory with strict permissions. | ||
1322 | */ | ||
1323 | for (cp = path; cp != NULL;) { | ||
1324 | if ((cp = strchr(cp, '/')) == NULL) | ||
1325 | strlcpy(component, path, sizeof(component)); | ||
1326 | else { | ||
1327 | cp++; | ||
1328 | memcpy(component, path, cp - path); | ||
1329 | component[cp - path] = '\0'; | ||
1330 | } | ||
1331 | |||
1332 | debug3("%s: checking '%s'", __func__, component); | ||
1333 | |||
1334 | if (stat(component, &st) != 0) | ||
1335 | fatal("%s: stat(\"%s\"): %s", __func__, | ||
1336 | component, strerror(errno)); | ||
1337 | if (st.st_uid != 0 || (st.st_mode & 022) != 0) | ||
1338 | fatal("bad ownership or modes for chroot " | ||
1339 | "directory %s\"%s\"", | ||
1340 | cp == NULL ? "" : "component ", component); | ||
1341 | if (!S_ISDIR(st.st_mode)) | ||
1342 | fatal("chroot path %s\"%s\" is not a directory", | ||
1343 | cp == NULL ? "" : "component ", component); | ||
1344 | |||
1345 | } | ||
1346 | |||
1347 | if (chdir(path) == -1) | ||
1348 | fatal("Unable to chdir to chroot path \"%s\": " | ||
1349 | "%s", path, strerror(errno)); | ||
1350 | if (chroot(path) == -1) | ||
1351 | fatal("chroot(\"%s\"): %s", path, strerror(errno)); | ||
1352 | if (chdir("/") == -1) | ||
1353 | fatal("%s: chdir(/) after chroot: %s", | ||
1354 | __func__, strerror(errno)); | ||
1355 | verbose("Changed root directory to \"%s\"", path); | ||
1356 | } | ||
1357 | |||
1296 | /* Set login name, uid, gid, and groups. */ | 1358 | /* Set login name, uid, gid, and groups. */ |
1297 | void | 1359 | void |
1298 | do_setusercontext(struct passwd *pw) | 1360 | do_setusercontext(struct passwd *pw) |
@@ -1324,7 +1386,7 @@ do_setusercontext(struct passwd *pw) | |||
1324 | } | 1386 | } |
1325 | # endif /* USE_PAM */ | 1387 | # endif /* USE_PAM */ |
1326 | if (setusercontext(lc, pw, pw->pw_uid, | 1388 | if (setusercontext(lc, pw, pw->pw_uid, |
1327 | (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { | 1389 | (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { |
1328 | perror("unable to set user context"); | 1390 | perror("unable to set user context"); |
1329 | exit(1); | 1391 | exit(1); |
1330 | } | 1392 | } |
@@ -1347,13 +1409,13 @@ do_setusercontext(struct passwd *pw) | |||
1347 | exit(1); | 1409 | exit(1); |
1348 | } | 1410 | } |
1349 | endgrent(); | 1411 | endgrent(); |
1350 | #ifdef GSSAPI | 1412 | # ifdef GSSAPI |
1351 | if (options.gss_authentication) { | 1413 | if (options.gss_authentication) { |
1352 | temporarily_use_uid(pw); | 1414 | temporarily_use_uid(pw); |
1353 | ssh_gssapi_storecreds(); | 1415 | ssh_gssapi_storecreds(); |
1354 | restore_uid(); | 1416 | restore_uid(); |
1355 | } | 1417 | } |
1356 | #endif | 1418 | # endif |
1357 | # ifdef USE_PAM | 1419 | # ifdef USE_PAM |
1358 | /* | 1420 | /* |
1359 | * PAM credentials may take the form of supplementary groups. | 1421 | * PAM credentials may take the form of supplementary groups. |
@@ -1367,15 +1429,33 @@ do_setusercontext(struct passwd *pw) | |||
1367 | # endif /* USE_PAM */ | 1429 | # endif /* USE_PAM */ |
1368 | # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) | 1430 | # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) |
1369 | irix_setusercontext(pw); | 1431 | irix_setusercontext(pw); |
1370 | # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ | 1432 | # endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ |
1371 | # ifdef _AIX | 1433 | # ifdef _AIX |
1372 | aix_usrinfo(pw); | 1434 | aix_usrinfo(pw); |
1373 | # endif /* _AIX */ | 1435 | # endif /* _AIX */ |
1374 | #ifdef USE_LIBIAF | 1436 | # ifdef USE_LIBIAF |
1375 | if (set_id(pw->pw_name) != 0) { | 1437 | if (set_id(pw->pw_name) != 0) { |
1376 | exit(1); | 1438 | exit(1); |
1377 | } | 1439 | } |
1378 | #endif /* USE_LIBIAF */ | 1440 | # endif /* USE_LIBIAF */ |
1441 | #endif | ||
1442 | |||
1443 | if (options.chroot_directory != NULL && | ||
1444 | strcasecmp(options.chroot_directory, "none") != 0) { | ||
1445 | char *chroot_path; | ||
1446 | |||
1447 | chroot_path = percent_expand(options.chroot_directory, | ||
1448 | "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL); | ||
1449 | safely_chroot(chroot_path, pw->pw_uid); | ||
1450 | free(chroot_path); | ||
1451 | } | ||
1452 | |||
1453 | #ifdef HAVE_LOGIN_CAP | ||
1454 | if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) { | ||
1455 | perror("unable to set user context (setuser)"); | ||
1456 | exit(1); | ||
1457 | } | ||
1458 | #else | ||
1379 | /* Permanently switch to the desired uid. */ | 1459 | /* Permanently switch to the desired uid. */ |
1380 | permanently_set_uid(pw); | 1460 | permanently_set_uid(pw); |
1381 | #endif | 1461 | #endif |
@@ -1625,7 +1705,7 @@ do_child(Session *s, const char *command) | |||
1625 | argv[i] = NULL; | 1705 | argv[i] = NULL; |
1626 | optind = optreset = 1; | 1706 | optind = optreset = 1; |
1627 | __progname = argv[0]; | 1707 | __progname = argv[0]; |
1628 | exit(sftp_server_main(i, argv)); | 1708 | exit(sftp_server_main(i, argv, s->pw)); |
1629 | } | 1709 | } |
1630 | 1710 | ||
1631 | if (options.use_login) { | 1711 | if (options.use_login) { |
@@ -1900,7 +1980,7 @@ session_subsystem_req(Session *s) | |||
1900 | if (strcmp(subsys, options.subsystem_name[i]) == 0) { | 1980 | if (strcmp(subsys, options.subsystem_name[i]) == 0) { |
1901 | prog = options.subsystem_command[i]; | 1981 | prog = options.subsystem_command[i]; |
1902 | cmd = options.subsystem_args[i]; | 1982 | cmd = options.subsystem_args[i]; |
1903 | if (!strcmp("internal-sftp", prog)) { | 1983 | if (!strcmp(INTERNAL_SFTP_NAME, prog)) { |
1904 | s->is_subsystem = SUBSYSTEM_INT_SFTP; | 1984 | s->is_subsystem = SUBSYSTEM_INT_SFTP; |
1905 | } else if (stat(prog, &st) < 0) { | 1985 | } else if (stat(prog, &st) < 0) { |
1906 | error("subsystem: cannot stat %s: %s", prog, | 1986 | error("subsystem: cannot stat %s: %s", prog, |
diff --git a/sftp-server-main.c b/sftp-server-main.c new file mode 100644 index 000000000..1d2ea6220 --- /dev/null +++ b/sftp-server-main.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* $OpenBSD: */ | ||
2 | /* | ||
3 | * Copyright (c) 2008 Markus Friedl. All rights reserved. | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include "includes.h" | ||
19 | |||
20 | #include <sys/types.h> | ||
21 | #include <pwd.h> | ||
22 | #include <stdarg.h> | ||
23 | #include <stdio.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include "log.h" | ||
27 | #include "sftp.h" | ||
28 | #include "misc.h" | ||
29 | |||
30 | void | ||
31 | cleanup_exit(int i) | ||
32 | { | ||
33 | sftp_server_cleanup_exit(i); | ||
34 | } | ||
35 | |||
36 | int | ||
37 | main(int argc, char **argv) | ||
38 | { | ||
39 | struct passwd *user_pw; | ||
40 | |||
41 | /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ | ||
42 | sanitise_stdfd(); | ||
43 | |||
44 | if ((user_pw = getpwuid(getuid())) == NULL) { | ||
45 | fprintf(stderr, "No user found for uid %lu", (u_long)getuid()); | ||
46 | return 1; | ||
47 | } | ||
48 | |||
49 | return (sftp_server_main(argc, argv, user_pw)); | ||
50 | } | ||
diff --git a/sftp-server.c b/sftp-server.c index 373bd5eda..44ccefff8 100644 --- a/sftp-server.c +++ b/sftp-server.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-server.c,v 1.76 2008/02/04 21:53:00 markus Exp $ */ | 1 | /* $OpenBSD: sftp-server.c,v 1.77 2008/02/08 23:24:07 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -1219,7 +1219,7 @@ sftp_server_usage(void) | |||
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | int | 1221 | int |
1222 | sftp_server_main(int argc, char **argv) | 1222 | sftp_server_main(int argc, char **argv, struct passwd *user_pw) |
1223 | { | 1223 | { |
1224 | fd_set *rset, *wset; | 1224 | fd_set *rset, *wset; |
1225 | int in, out, max, ch, skipargs = 0, log_stderr = 0; | 1225 | int in, out, max, ch, skipargs = 0, log_stderr = 0; |
@@ -1277,11 +1277,7 @@ sftp_server_main(int argc, char **argv) | |||
1277 | } else | 1277 | } else |
1278 | client_addr = xstrdup("UNKNOWN"); | 1278 | client_addr = xstrdup("UNKNOWN"); |
1279 | 1279 | ||
1280 | if ((pw = getpwuid(getuid())) == NULL) { | 1280 | pw = pwcopy(user_pw); |
1281 | error("No user found for uid %lu", (u_long)getuid()); | ||
1282 | sftp_server_cleanup_exit(255); | ||
1283 | } | ||
1284 | pw = pwcopy(pw); | ||
1285 | 1281 | ||
1286 | logit("session opened for local user %s from [%s]", | 1282 | logit("session opened for local user %s from [%s]", |
1287 | pw->pw_name, client_addr); | 1283 | pw->pw_name, client_addr); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.h,v 1.6 2008/02/04 21:53:00 markus Exp $ */ | 1 | /* $OpenBSD: sftp.h,v 1.7 2008/02/08 23:24:07 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
@@ -91,5 +91,7 @@ | |||
91 | #define SSH2_FX_OP_UNSUPPORTED 8 | 91 | #define SSH2_FX_OP_UNSUPPORTED 8 |
92 | #define SSH2_FX_MAX 8 | 92 | #define SSH2_FX_MAX 8 |
93 | 93 | ||
94 | int sftp_server_main(int, char **); | 94 | struct passwd; |
95 | |||
96 | int sftp_server_main(int, char **, struct passwd *); | ||
95 | void sftp_server_cleanup_exit(int) __dead; | 97 | void sftp_server_cleanup_exit(int) __dead; |
diff --git a/sshd_config b/sshd_config index c7094e775..ddfbbe91e 100644 --- a/sshd_config +++ b/sshd_config | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: sshd_config,v 1.76 2007/08/23 03:22:16 djm Exp $ | 1 | # $OpenBSD: sshd_config,v 1.77 2008/02/08 23:24:07 djm Exp $ |
2 | 2 | ||
3 | # This is the sshd server system-wide configuration file. See | 3 | # This is the sshd server system-wide configuration file. See |
4 | # sshd_config(5) for more information. | 4 | # sshd_config(5) for more information. |
@@ -102,6 +102,7 @@ Protocol 2 | |||
102 | #PidFile /var/run/sshd.pid | 102 | #PidFile /var/run/sshd.pid |
103 | #MaxStartups 10 | 103 | #MaxStartups 10 |
104 | #PermitTunnel no | 104 | #PermitTunnel no |
105 | #ChrootDirectory none | ||
105 | 106 | ||
106 | # no default banner path | 107 | # no default banner path |
107 | #Banner none | 108 | #Banner none |
diff --git a/sshd_config.5 b/sshd_config.5 index aa6720dc3..2f83bf2e1 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -34,8 +34,8 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: sshd_config.5,v 1.79 2008/01/01 09:27:33 dtucker Exp $ | 37 | .\" $OpenBSD: sshd_config.5,v 1.80 2008/02/08 23:24:07 djm Exp $ |
38 | .Dd $Mdocdate: January 1 2008 $ | 38 | .Dd $Mdocdate: February 8 2008 $ |
39 | .Dt SSHD_CONFIG 5 | 39 | .Dt SSHD_CONFIG 5 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -173,6 +173,45 @@ All authentication styles from | |||
173 | are supported. | 173 | are supported. |
174 | The default is | 174 | The default is |
175 | .Dq yes . | 175 | .Dq yes . |
176 | .It Cm ChrootDirectory | ||
177 | Specifies a path to | ||
178 | .Xr chroot 2 | ||
179 | to after authentication. | ||
180 | This path, and all its components, must be root-owned directories that are | ||
181 | not writable by any other user or group. | ||
182 | .Pp | ||
183 | The path may contain the following tokens that are expanded at runtime once | ||
184 | the connecting user has been authenticated: %% is replaced by a literal '%', | ||
185 | %h is replaced by the home directory of the user being authenticated, and | ||
186 | %u is replaced by the username of that user. | ||
187 | .Pp | ||
188 | The | ||
189 | .Cm ChrootDirectory | ||
190 | must contain the necessary files and directories to support the | ||
191 | users' session. | ||
192 | For an interactive session this requires at least a shell, typically | ||
193 | .Xr sh 1 , | ||
194 | and basic | ||
195 | .Pa /dev | ||
196 | nodes such as | ||
197 | .Xr null 4 , | ||
198 | .Xr zero 4 , | ||
199 | .Xr stdin 4 , | ||
200 | .Xr stdout 4 , | ||
201 | .Xr stderr 4 , | ||
202 | .Xr arandom 4 | ||
203 | and | ||
204 | .Xr tty 4 | ||
205 | devices. | ||
206 | For file transfer sessions using | ||
207 | .Dq sftp , | ||
208 | no additional configuration of the environment is necessary if the | ||
209 | in-process sftp server is used (see | ||
210 | .Cm Subsystem | ||
211 | for details. | ||
212 | .Pp | ||
213 | The default is not to | ||
214 | .Xr chroot 2 . | ||
176 | .It Cm Ciphers | 215 | .It Cm Ciphers |
177 | Specifies the ciphers allowed for protocol version 2. | 216 | Specifies the ciphers allowed for protocol version 2. |
178 | Multiple ciphers must be comma-separated. | 217 | Multiple ciphers must be comma-separated. |
@@ -740,11 +779,22 @@ The default is | |||
740 | Configures an external subsystem (e.g. file transfer daemon). | 779 | Configures an external subsystem (e.g. file transfer daemon). |
741 | Arguments should be a subsystem name and a command (with optional arguments) | 780 | Arguments should be a subsystem name and a command (with optional arguments) |
742 | to execute upon subsystem request. | 781 | to execute upon subsystem request. |
782 | .Pp | ||
743 | The command | 783 | The command |
744 | .Xr sftp-server 8 | 784 | .Xr sftp-server 8 |
745 | implements the | 785 | implements the |
746 | .Dq sftp | 786 | .Dq sftp |
747 | file transfer subsystem. | 787 | file transfer subsystem. |
788 | .Pp | ||
789 | Alternately the name | ||
790 | .Dq internal-sftp | ||
791 | implements an in-process | ||
792 | .Dq sftp | ||
793 | server. | ||
794 | This may simplify configurations using | ||
795 | .Cm ChrootDirectory | ||
796 | to force a different filesystem root on clients. | ||
797 | .Pp | ||
748 | By default no subsystems are defined. | 798 | By default no subsystems are defined. |
749 | Note that this option applies to protocol version 2 only. | 799 | Note that this option applies to protocol version 2 only. |
750 | .It Cm SyslogFacility | 800 | .It Cm SyslogFacility |