diff options
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | configure.ac | 38 | ||||
-rw-r--r-- | mux.c | 2 | ||||
-rw-r--r-- | openbsd-compat/port-solaris.c | 114 | ||||
-rw-r--r-- | openbsd-compat/port-solaris.h | 3 | ||||
-rw-r--r-- | platform-pledge.c | 71 | ||||
-rw-r--r-- | platform.h | 5 | ||||
-rw-r--r-- | sandbox-solaris.c | 107 | ||||
-rw-r--r-- | sftp-server.c | 3 | ||||
-rw-r--r-- | ssh-agent.c | 1 | ||||
-rw-r--r-- | uidswap.c | 18 |
11 files changed, 358 insertions, 10 deletions
diff --git a/Makefile.in b/Makefile.in index 15cf69e1f..9e326411c 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -91,7 +91,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ | |||
91 | sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ | 91 | sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ |
92 | kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ | 92 | kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ |
93 | kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ | 93 | kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ |
94 | kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o | 94 | kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ |
95 | platform-pledge.o | ||
95 | 96 | ||
96 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ | 97 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ |
97 | sshconnect.o sshconnect1.o sshconnect2.o mux.o \ | 98 | sshconnect.o sshconnect1.o sshconnect2.o mux.o \ |
@@ -110,7 +111,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ | |||
110 | sftp-server.o sftp-common.o \ | 111 | sftp-server.o sftp-common.o \ |
111 | roaming_common.o roaming_serv.o \ | 112 | roaming_common.o roaming_serv.o \ |
112 | sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ | 113 | sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ |
113 | sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o | 114 | sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ |
115 | sandbox-solaris.o | ||
114 | 116 | ||
115 | MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out | 117 | MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out |
116 | MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 | 118 | MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 |
diff --git a/configure.ac b/configure.ac index b6854320c..0b399ce2c 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -469,6 +469,11 @@ AC_CHECK_HEADERS([sys/un.h], [], [], [ | |||
469 | SIA_MSG="no" | 469 | SIA_MSG="no" |
470 | SPC_MSG="no" | 470 | SPC_MSG="no" |
471 | SP_MSG="no" | 471 | SP_MSG="no" |
472 | SPP_MSG="no" | ||
473 | |||
474 | # Support for Solaris/Illumos privileges (this test is used by both | ||
475 | # the --with-solaris-privs option and --with-sandbox=solaris). | ||
476 | SOLARIS_PRIVS="no" | ||
472 | 477 | ||
473 | # Check for some target-specific stuff | 478 | # Check for some target-specific stuff |
474 | case "$host" in | 479 | case "$host" in |
@@ -575,6 +580,8 @@ case "$host" in | |||
575 | LIBS="$LIBS /usr/lib/textreadmode.o" | 580 | LIBS="$LIBS /usr/lib/textreadmode.o" |
576 | AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin]) | 581 | AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin]) |
577 | AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()]) | 582 | AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()]) |
583 | AC_DEFINE([NO_UID_RESTORATION_TEST], [1], | ||
584 | [Define to disable UID restoration test]) | ||
578 | AC_DEFINE([DISABLE_SHADOW], [1], | 585 | AC_DEFINE([DISABLE_SHADOW], [1], |
579 | [Define if you want to disable shadow passwords]) | 586 | [Define if you want to disable shadow passwords]) |
580 | AC_DEFINE([NO_X11_UNIX_SOCKETS], [1], | 587 | AC_DEFINE([NO_X11_UNIX_SOCKETS], [1], |
@@ -889,13 +896,18 @@ mips-sony-bsd|mips-sony-newsos4) | |||
889 | else | 896 | else |
890 | AC_MSG_RESULT([no]) | 897 | AC_MSG_RESULT([no]) |
891 | fi | 898 | fi |
899 | AC_CHECK_FUNC([setppriv], | ||
900 | [ AC_CHECK_HEADERS([priv.h], [ | ||
901 | SOLARIS_PRIVS="yes" | ||
902 | ]) | ||
903 | ]) | ||
892 | AC_ARG_WITH([solaris-contracts], | 904 | AC_ARG_WITH([solaris-contracts], |
893 | [ --with-solaris-contracts Enable Solaris process contracts (experimental)], | 905 | [ --with-solaris-contracts Enable Solaris process contracts (experimental)], |
894 | [ | 906 | [ |
895 | AC_CHECK_LIB([contract], [ct_tmpl_activate], | 907 | AC_CHECK_LIB([contract], [ct_tmpl_activate], |
896 | [ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1], | 908 | [ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1], |
897 | [Define if you have Solaris process contracts]) | 909 | [Define if you have Solaris process contracts]) |
898 | SSHDLIBS="$SSHDLIBS -lcontract" | 910 | LIBS="$LIBS -lcontract" |
899 | SPC_MSG="yes" ], ) | 911 | SPC_MSG="yes" ], ) |
900 | ], | 912 | ], |
901 | ) | 913 | ) |
@@ -905,10 +917,27 @@ mips-sony-bsd|mips-sony-newsos4) | |||
905 | AC_CHECK_LIB([project], [setproject], | 917 | AC_CHECK_LIB([project], [setproject], |
906 | [ AC_DEFINE([USE_SOLARIS_PROJECTS], [1], | 918 | [ AC_DEFINE([USE_SOLARIS_PROJECTS], [1], |
907 | [Define if you have Solaris projects]) | 919 | [Define if you have Solaris projects]) |
908 | SSHDLIBS="$SSHDLIBS -lproject" | 920 | LIBS="$LIBS -lproject" |
909 | SP_MSG="yes" ], ) | 921 | SP_MSG="yes" ], ) |
910 | ], | 922 | ], |
911 | ) | 923 | ) |
924 | AC_ARG_WITH([solaris-privs], | ||
925 | [ --with-solaris-privs Enable Solaris/Illumos privileges (experimental)], | ||
926 | [ | ||
927 | AC_MSG_CHECKING([for Solaris/Illumos privilege support]) | ||
928 | if test "x$SOLARIS_PRIVS" = "xyes" ; then | ||
929 | AC_MSG_RESULT([found]) | ||
930 | AC_DEFINE([NO_UID_RESTORATION_TEST], [1], | ||
931 | [Define to disable UID restoration test]) | ||
932 | AC_DEFINE([USE_SOLARIS_PRIVS], [1], | ||
933 | [Define if you have Solaris privileges]) | ||
934 | SPP_MSG="yes" | ||
935 | else | ||
936 | AC_MSG_RESULT([not found]) | ||
937 | AC_MSG_ERROR([*** must have support for Solaris privileges to use --with-solaris-privs]) | ||
938 | fi | ||
939 | ], | ||
940 | ) | ||
912 | TEST_SHELL=$SHELL # let configure find us a capable shell | 941 | TEST_SHELL=$SHELL # let configure find us a capable shell |
913 | ;; | 942 | ;; |
914 | *-*-sunos4*) | 943 | *-*-sunos4*) |
@@ -3156,6 +3185,10 @@ elif test "x$sandbox_arg" = "xrlimit" || \ | |||
3156 | AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit]) | 3185 | AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit]) |
3157 | SANDBOX_STYLE="rlimit" | 3186 | SANDBOX_STYLE="rlimit" |
3158 | AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)]) | 3187 | AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)]) |
3188 | elif test "x$sandbox_arg" = "xsolaris" || \ | ||
3189 | ( test -z "$sandbox_arg" && test "x$SOLARIS_PRIVS" = "xyes" ) ; then | ||
3190 | SANDBOX_STYLE="solaris" | ||
3191 | AC_DEFINE([SANDBOX_SOLARIS], [1], [Sandbox using Solaris/Illumos privileges]) | ||
3159 | elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ | 3192 | elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \ |
3160 | test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then | 3193 | test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then |
3161 | SANDBOX_STYLE="none" | 3194 | SANDBOX_STYLE="none" |
@@ -4945,6 +4978,7 @@ echo " MD5 password support: $MD5_MSG" | |||
4945 | echo " libedit support: $LIBEDIT_MSG" | 4978 | echo " libedit support: $LIBEDIT_MSG" |
4946 | echo " Solaris process contract support: $SPC_MSG" | 4979 | echo " Solaris process contract support: $SPC_MSG" |
4947 | echo " Solaris project support: $SP_MSG" | 4980 | echo " Solaris project support: $SP_MSG" |
4981 | echo " Solaris privilege support: $SPP_MSG" | ||
4948 | echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" | 4982 | echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" |
4949 | echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" | 4983 | echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" |
4950 | echo " BSD Auth support: $BSD_AUTH_MSG" | 4984 | echo " BSD Auth support: $BSD_AUTH_MSG" |
@@ -1891,6 +1891,7 @@ mux_client_request_session(int fd) | |||
1891 | 1891 | ||
1892 | if (pledge("stdio proc tty", NULL) == -1) | 1892 | if (pledge("stdio proc tty", NULL) == -1) |
1893 | fatal("%s pledge(): %s", __func__, strerror(errno)); | 1893 | fatal("%s pledge(): %s", __func__, strerror(errno)); |
1894 | platform_pledge_mux(); | ||
1894 | 1895 | ||
1895 | signal(SIGHUP, control_client_sighandler); | 1896 | signal(SIGHUP, control_client_sighandler); |
1896 | signal(SIGINT, control_client_sighandler); | 1897 | signal(SIGINT, control_client_sighandler); |
@@ -2001,6 +2002,7 @@ mux_client_request_stdio_fwd(int fd) | |||
2001 | 2002 | ||
2002 | if (pledge("stdio proc tty", NULL) == -1) | 2003 | if (pledge("stdio proc tty", NULL) == -1) |
2003 | fatal("%s pledge(): %s", __func__, strerror(errno)); | 2004 | fatal("%s pledge(): %s", __func__, strerror(errno)); |
2005 | platform_pledge_mux(); | ||
2004 | 2006 | ||
2005 | debug3("%s: stdio forward request sent", __func__); | 2007 | debug3("%s: stdio forward request sent", __func__); |
2006 | 2008 | ||
diff --git a/openbsd-compat/port-solaris.c b/openbsd-compat/port-solaris.c index 25382f1c9..962cd1685 100644 --- a/openbsd-compat/port-solaris.c +++ b/openbsd-compat/port-solaris.c | |||
@@ -227,3 +227,117 @@ solaris_set_default_project(struct passwd *pw) | |||
227 | } | 227 | } |
228 | } | 228 | } |
229 | #endif /* USE_SOLARIS_PROJECTS */ | 229 | #endif /* USE_SOLARIS_PROJECTS */ |
230 | |||
231 | #ifdef USE_SOLARIS_PRIVS | ||
232 | # ifdef HAVE_PRIV_H | ||
233 | # include <priv.h> | ||
234 | # endif | ||
235 | |||
236 | void | ||
237 | solaris_drop_privs_pinfo_net_fork_exec(void) | ||
238 | { | ||
239 | priv_set_t *pset = NULL, *npset = NULL; | ||
240 | |||
241 | /* | ||
242 | * Note: this variant avoids dropping DAC filesystem rights, in case | ||
243 | * the process calling it is running as root and should have the | ||
244 | * ability to read/write/chown any file on the system. | ||
245 | * | ||
246 | * We start with the basic set, then *add* the DAC rights to it while | ||
247 | * taking away other parts of BASIC we don't need. Then we intersect | ||
248 | * this with our existing PERMITTED set. In this way we keep any | ||
249 | * DAC rights we had before, while otherwise reducing ourselves to | ||
250 | * the minimum set of privileges we need to proceed. | ||
251 | * | ||
252 | * This also means we drop any other parts of "root" that we don't | ||
253 | * need (e.g. the ability to kill any process, create new device nodes | ||
254 | * etc etc). | ||
255 | */ | ||
256 | |||
257 | if ((pset = priv_allocset()) == NULL || | ||
258 | (npset = priv_allocset()) == NULL) | ||
259 | fatal("priv_allocset: %s", strerror(errno)); | ||
260 | |||
261 | priv_basicset(npset); | ||
262 | |||
263 | if (priv_addset(npset, PRIV_FILE_CHOWN) != 0 || | ||
264 | priv_addset(npset, PRIV_FILE_DAC_READ) != 0 || | ||
265 | priv_addset(npset, PRIV_FILE_DAC_SEARCH) != 0 || | ||
266 | priv_addset(npset, PRIV_FILE_DAC_WRITE) != 0 || | ||
267 | priv_addset(npset, PRIV_FILE_OWNER) != 0) | ||
268 | fatal("priv_addset: %s", strerror(errno)); | ||
269 | |||
270 | if (priv_delset(npset, PRIV_FILE_LINK_ANY) != 0 || | ||
271 | priv_delset(npset, PRIV_NET_ACCESS) != 0 || | ||
272 | priv_delset(npset, PRIV_PROC_EXEC) != 0 || | ||
273 | priv_delset(npset, PRIV_PROC_FORK) != 0 || | ||
274 | priv_delset(npset, PRIV_PROC_INFO) != 0 || | ||
275 | priv_delset(npset, PRIV_PROC_SESSION) != 0) | ||
276 | fatal("priv_delset: %s", strerror(errno)); | ||
277 | |||
278 | if (getppriv(PRIV_PERMITTED, pset) != 0) | ||
279 | fatal("getppriv: %s", strerror(errno)); | ||
280 | |||
281 | priv_intersect(pset, npset); | ||
282 | |||
283 | if (setppriv(PRIV_SET, PRIV_PERMITTED, npset) != 0 || | ||
284 | setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0 || | ||
285 | setppriv(PRIV_SET, PRIV_INHERITABLE, npset) != 0) | ||
286 | fatal("setppriv: %s", strerror(errno)); | ||
287 | |||
288 | priv_freeset(pset); | ||
289 | priv_freeset(npset); | ||
290 | } | ||
291 | |||
292 | void | ||
293 | solaris_drop_privs_root_pinfo_net(void) | ||
294 | { | ||
295 | priv_set_t *pset = NULL; | ||
296 | |||
297 | if ((pset = priv_allocset()) == NULL) | ||
298 | fatal("priv_allocset: %s", strerror(errno)); | ||
299 | |||
300 | /* Start with "basic" and drop everything we don't need. */ | ||
301 | priv_basicset(pset); | ||
302 | |||
303 | if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 || | ||
304 | priv_delset(pset, PRIV_NET_ACCESS) != 0 || | ||
305 | priv_delset(pset, PRIV_PROC_INFO) != 0 || | ||
306 | priv_delset(pset, PRIV_PROC_SESSION) != 0) | ||
307 | fatal("priv_delset: %s", strerror(errno)); | ||
308 | |||
309 | if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 || | ||
310 | setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 || | ||
311 | setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0) | ||
312 | fatal("setppriv: %s", strerror(errno)); | ||
313 | |||
314 | priv_freeset(pset); | ||
315 | } | ||
316 | |||
317 | void | ||
318 | solaris_drop_privs_root_pinfo_net_exec(void) | ||
319 | { | ||
320 | priv_set_t *pset = NULL; | ||
321 | |||
322 | if ((pset = priv_allocset()) == NULL) | ||
323 | fatal("priv_allocset: %s", strerror(errno)); | ||
324 | |||
325 | /* Start with "basic" and drop everything we don't need. */ | ||
326 | priv_basicset(pset); | ||
327 | |||
328 | if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 || | ||
329 | priv_delset(pset, PRIV_NET_ACCESS) != 0 || | ||
330 | priv_delset(pset, PRIV_PROC_EXEC) != 0 || | ||
331 | priv_delset(pset, PRIV_PROC_INFO) != 0 || | ||
332 | priv_delset(pset, PRIV_PROC_SESSION) != 0) | ||
333 | fatal("priv_delset: %s", strerror(errno)); | ||
334 | |||
335 | if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 || | ||
336 | setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 || | ||
337 | setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0) | ||
338 | fatal("setppriv: %s", strerror(errno)); | ||
339 | |||
340 | priv_freeset(pset); | ||
341 | } | ||
342 | |||
343 | #endif | ||
diff --git a/openbsd-compat/port-solaris.h b/openbsd-compat/port-solaris.h index cd442e78b..b077e186a 100644 --- a/openbsd-compat/port-solaris.h +++ b/openbsd-compat/port-solaris.h | |||
@@ -26,5 +26,8 @@ void solaris_contract_pre_fork(void); | |||
26 | void solaris_contract_post_fork_child(void); | 26 | void solaris_contract_post_fork_child(void); |
27 | void solaris_contract_post_fork_parent(pid_t pid); | 27 | void solaris_contract_post_fork_parent(pid_t pid); |
28 | void solaris_set_default_project(struct passwd *); | 28 | void solaris_set_default_project(struct passwd *); |
29 | void solaris_drop_privs_pinfo_net_fork_exec(void); | ||
30 | void solaris_drop_privs_root_pinfo_net(void); | ||
31 | void solaris_drop_privs_root_pinfo_net_exec(void); | ||
29 | 32 | ||
30 | #endif | 33 | #endif |
diff --git a/platform-pledge.c b/platform-pledge.c new file mode 100644 index 000000000..4a6ec15e1 --- /dev/null +++ b/platform-pledge.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Joyent, Inc | ||
3 | * Author: Alex Wilson <alex.wilson@joyent.com> | ||
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 | |||
22 | #include <stdarg.h> | ||
23 | #include <unistd.h> | ||
24 | |||
25 | #include "platform.h" | ||
26 | |||
27 | #include "openbsd-compat/openbsd-compat.h" | ||
28 | |||
29 | /* | ||
30 | * Drop any fine-grained privileges that are not needed for post-startup | ||
31 | * operation of ssh-agent | ||
32 | * | ||
33 | * Should be as close as possible to pledge("stdio cpath unix id proc exec", ...) | ||
34 | */ | ||
35 | void | ||
36 | platform_pledge_agent(void) | ||
37 | { | ||
38 | #ifdef USE_SOLARIS_PRIVS | ||
39 | /* | ||
40 | * Note: Solaris priv dropping is closer to tame() than pledge(), but | ||
41 | * we will use what we have. | ||
42 | */ | ||
43 | solaris_drop_privs_root_pinfo_net(); | ||
44 | #endif | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Drop any fine-grained privileges that are not needed for post-startup | ||
49 | * operation of sftp-server | ||
50 | */ | ||
51 | void | ||
52 | platform_pledge_sftp_server(void) | ||
53 | { | ||
54 | #ifdef USE_SOLARIS_PRIVS | ||
55 | solaris_drop_privs_pinfo_net_fork_exec(); | ||
56 | #endif | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Drop any fine-grained privileges that are not needed for the post-startup | ||
61 | * operation of the SSH client mux | ||
62 | * | ||
63 | * Should be as close as possible to pledge("stdio proc tty", ...) | ||
64 | */ | ||
65 | void | ||
66 | platform_pledge_mux(void) | ||
67 | { | ||
68 | #ifdef USE_SOLARIS_PRIVS | ||
69 | solaris_drop_privs_root_pinfo_net_exec(); | ||
70 | #endif | ||
71 | } | ||
diff --git a/platform.h b/platform.h index 1c7a45d8f..e687c99b6 100644 --- a/platform.h +++ b/platform.h | |||
@@ -31,3 +31,8 @@ void platform_setusercontext_post_groups(struct passwd *); | |||
31 | char *platform_get_krb5_client(const char *); | 31 | char *platform_get_krb5_client(const char *); |
32 | char *platform_krb5_get_principal_name(const char *); | 32 | char *platform_krb5_get_principal_name(const char *); |
33 | int platform_sys_dir_uid(uid_t); | 33 | int platform_sys_dir_uid(uid_t); |
34 | |||
35 | /* in platform-pledge.c */ | ||
36 | void platform_pledge_agent(void); | ||
37 | void platform_pledge_sftp_server(void); | ||
38 | void platform_pledge_mux(void); | ||
diff --git a/sandbox-solaris.c b/sandbox-solaris.c new file mode 100644 index 000000000..98714e170 --- /dev/null +++ b/sandbox-solaris.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Joyent, Inc | ||
3 | * Author: Alex Wilson <alex.wilson@joyent.com> | ||
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 | #ifdef SANDBOX_SOLARIS | ||
21 | #ifndef USE_SOLARIS_PRIVS | ||
22 | # error "--with-solaris-privs must be used with the Solaris sandbox" | ||
23 | #endif | ||
24 | |||
25 | #include <sys/types.h> | ||
26 | |||
27 | #include <errno.h> | ||
28 | #include <stdarg.h> | ||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <unistd.h> | ||
33 | #ifdef HAVE_PRIV_H | ||
34 | # include <priv.h> | ||
35 | #endif | ||
36 | |||
37 | #include "log.h" | ||
38 | #include "ssh-sandbox.h" | ||
39 | #include "xmalloc.h" | ||
40 | |||
41 | struct ssh_sandbox { | ||
42 | priv_set_t *pset; | ||
43 | }; | ||
44 | |||
45 | struct ssh_sandbox * | ||
46 | ssh_sandbox_init(struct monitor *monitor) | ||
47 | { | ||
48 | struct ssh_sandbox *box = NULL; | ||
49 | |||
50 | box = xcalloc(1, sizeof(*box)); | ||
51 | box->pset = priv_allocset(); | ||
52 | |||
53 | if (box->pset == NULL) { | ||
54 | free(box); | ||
55 | return NULL; | ||
56 | } | ||
57 | |||
58 | /* Start with "basic" and drop everything we don't need. */ | ||
59 | priv_basicset(box->pset); | ||
60 | |||
61 | /* Drop everything except the ability to use already-opened files */ | ||
62 | if (priv_delset(box->pset, PRIV_FILE_LINK_ANY) != 0 || | ||
63 | priv_delset(box->pset, PRIV_NET_ACCESS) != 0 || | ||
64 | priv_delset(box->pset, PRIV_PROC_EXEC) != 0 || | ||
65 | priv_delset(box->pset, PRIV_PROC_FORK) != 0 || | ||
66 | priv_delset(box->pset, PRIV_PROC_INFO) != 0 || | ||
67 | priv_delset(box->pset, PRIV_PROC_SESSION) != 0) { | ||
68 | free(box); | ||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | /* These may not be available on older Solaris-es */ | ||
73 | # if defined(PRIV_FILE_READ) && defined(PRIV_FILE_WRITE) | ||
74 | if (priv_delset(box->pset, PRIV_FILE_READ) != 0 || | ||
75 | priv_delset(box->pset, PRIV_FILE_WRITE) != 0) { | ||
76 | free(box); | ||
77 | return NULL; | ||
78 | } | ||
79 | # endif | ||
80 | |||
81 | return box; | ||
82 | } | ||
83 | |||
84 | void | ||
85 | ssh_sandbox_child(struct ssh_sandbox *box) | ||
86 | { | ||
87 | if (setppriv(PRIV_SET, PRIV_PERMITTED, box->pset) != 0 || | ||
88 | setppriv(PRIV_SET, PRIV_LIMIT, box->pset) != 0 || | ||
89 | setppriv(PRIV_SET, PRIV_INHERITABLE, box->pset) != 0) | ||
90 | fatal("setppriv: %s", strerror(errno)); | ||
91 | } | ||
92 | |||
93 | void | ||
94 | ssh_sandbox_parent_finish(struct ssh_sandbox *box) | ||
95 | { | ||
96 | priv_freeset(box->pset); | ||
97 | box->pset = NULL; | ||
98 | free(box); | ||
99 | } | ||
100 | |||
101 | void | ||
102 | ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) | ||
103 | { | ||
104 | /* Nothing to do here */ | ||
105 | } | ||
106 | |||
107 | #endif /* SANDBOX_SOLARIS */ | ||
diff --git a/sftp-server.c b/sftp-server.c index 62e76a505..79ef45b10 100644 --- a/sftp-server.c +++ b/sftp-server.c | |||
@@ -1598,6 +1598,9 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) | |||
1598 | fatal("unable to make the process undumpable"); | 1598 | fatal("unable to make the process undumpable"); |
1599 | #endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */ | 1599 | #endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */ |
1600 | 1600 | ||
1601 | /* Drop any fine-grained privileges we don't need */ | ||
1602 | platform_pledge_sftp_server(); | ||
1603 | |||
1601 | if ((cp = getenv("SSH_CONNECTION")) != NULL) { | 1604 | if ((cp = getenv("SSH_CONNECTION")) != NULL) { |
1602 | client_addr = xstrdup(cp); | 1605 | client_addr = xstrdup(cp); |
1603 | if ((cp = strchr(client_addr, ' ')) == NULL) { | 1606 | if ((cp = strchr(client_addr, ' ')) == NULL) { |
diff --git a/ssh-agent.c b/ssh-agent.c index 2048a11c4..6c50e0f03 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1417,6 +1417,7 @@ skip: | |||
1417 | 1417 | ||
1418 | if (pledge("stdio cpath unix id proc exec", NULL) == -1) | 1418 | if (pledge("stdio cpath unix id proc exec", NULL) == -1) |
1419 | fatal("%s: pledge: %s", __progname, strerror(errno)); | 1419 | fatal("%s: pledge: %s", __progname, strerror(errno)); |
1420 | platform_pledge_agent(); | ||
1420 | 1421 | ||
1421 | while (1) { | 1422 | while (1) { |
1422 | prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp); | 1423 | prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp); |
@@ -134,7 +134,7 @@ temporarily_use_uid(struct passwd *pw) | |||
134 | void | 134 | void |
135 | permanently_drop_suid(uid_t uid) | 135 | permanently_drop_suid(uid_t uid) |
136 | { | 136 | { |
137 | #ifndef HAVE_CYGWIN | 137 | #ifndef NO_UID_RESTORATION_TEST |
138 | uid_t old_uid = getuid(); | 138 | uid_t old_uid = getuid(); |
139 | #endif | 139 | #endif |
140 | 140 | ||
@@ -142,8 +142,14 @@ permanently_drop_suid(uid_t uid) | |||
142 | if (setresuid(uid, uid, uid) < 0) | 142 | if (setresuid(uid, uid, uid) < 0) |
143 | fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno)); | 143 | fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno)); |
144 | 144 | ||
145 | #ifndef HAVE_CYGWIN | 145 | #ifndef NO_UID_RESTORATION_TEST |
146 | /* Try restoration of UID if changed (test clearing of saved uid) */ | 146 | /* |
147 | * Try restoration of UID if changed (test clearing of saved uid). | ||
148 | * | ||
149 | * Note that we don't do this on Cygwin, or on Solaris-based platforms | ||
150 | * where fine-grained privileges are available (the user might be | ||
151 | * deliberately allowed the right to setuid back to root). | ||
152 | */ | ||
147 | if (old_uid != uid && | 153 | if (old_uid != uid && |
148 | (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) | 154 | (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) |
149 | fatal("%s: was able to restore old [e]uid", __func__); | 155 | fatal("%s: was able to restore old [e]uid", __func__); |
@@ -199,7 +205,7 @@ restore_uid(void) | |||
199 | void | 205 | void |
200 | permanently_set_uid(struct passwd *pw) | 206 | permanently_set_uid(struct passwd *pw) |
201 | { | 207 | { |
202 | #ifndef HAVE_CYGWIN | 208 | #ifndef NO_UID_RESTORATION_TEST |
203 | uid_t old_uid = getuid(); | 209 | uid_t old_uid = getuid(); |
204 | gid_t old_gid = getgid(); | 210 | gid_t old_gid = getgid(); |
205 | #endif | 211 | #endif |
@@ -227,7 +233,7 @@ permanently_set_uid(struct passwd *pw) | |||
227 | if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) | 233 | if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) |
228 | fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); | 234 | fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); |
229 | 235 | ||
230 | #ifndef HAVE_CYGWIN | 236 | #ifndef NO_UID_RESTORATION_TEST |
231 | /* Try restoration of GID if changed (test clearing of saved gid) */ | 237 | /* Try restoration of GID if changed (test clearing of saved gid) */ |
232 | if (old_gid != pw->pw_gid && pw->pw_uid != 0 && | 238 | if (old_gid != pw->pw_gid && pw->pw_uid != 0 && |
233 | (setgid(old_gid) != -1 || setegid(old_gid) != -1)) | 239 | (setgid(old_gid) != -1 || setegid(old_gid) != -1)) |
@@ -241,7 +247,7 @@ permanently_set_uid(struct passwd *pw) | |||
241 | (u_int)pw->pw_gid); | 247 | (u_int)pw->pw_gid); |
242 | } | 248 | } |
243 | 249 | ||
244 | #ifndef HAVE_CYGWIN | 250 | #ifndef NO_UID_RESTORATION_TEST |
245 | /* Try restoration of UID if changed (test clearing of saved uid) */ | 251 | /* Try restoration of UID if changed (test clearing of saved uid) */ |
246 | if (old_uid != pw->pw_uid && | 252 | if (old_uid != pw->pw_uid && |
247 | (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) | 253 | (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) |