mirror of
git://anongit.mindrot.org/openssh.git
synced 2025-01-03 00:02:05 +00:00
Support Illumos/Solaris fine-grained privileges
Includes a pre-auth privsep sandbox and several pledge() emulations. bz#2511, patch by Alex Wilson. ok dtucker@
This commit is contained in:
parent
422d1b3ee9
commit
4626cbaf78
@ -91,7 +91,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
|||||||
sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
|
sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
|
||||||
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
|
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
|
||||||
kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
|
kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
|
||||||
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o
|
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
|
||||||
|
platform-pledge.o
|
||||||
|
|
||||||
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
|
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
|
||||||
sshconnect.o sshconnect1.o sshconnect2.o mux.o \
|
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 \
|
|||||||
sftp-server.o sftp-common.o \
|
sftp-server.o sftp-common.o \
|
||||||
roaming_common.o roaming_serv.o \
|
roaming_common.o roaming_serv.o \
|
||||||
sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
|
sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
|
||||||
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o
|
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
|
||||||
|
sandbox-solaris.o
|
||||||
|
|
||||||
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
|
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
|
||||||
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
|
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
|
||||||
|
38
configure.ac
38
configure.ac
@ -469,6 +469,11 @@ AC_CHECK_HEADERS([sys/un.h], [], [], [
|
|||||||
SIA_MSG="no"
|
SIA_MSG="no"
|
||||||
SPC_MSG="no"
|
SPC_MSG="no"
|
||||||
SP_MSG="no"
|
SP_MSG="no"
|
||||||
|
SPP_MSG="no"
|
||||||
|
|
||||||
|
# Support for Solaris/Illumos privileges (this test is used by both
|
||||||
|
# the --with-solaris-privs option and --with-sandbox=solaris).
|
||||||
|
SOLARIS_PRIVS="no"
|
||||||
|
|
||||||
# Check for some target-specific stuff
|
# Check for some target-specific stuff
|
||||||
case "$host" in
|
case "$host" in
|
||||||
@ -575,6 +580,8 @@ case "$host" in
|
|||||||
LIBS="$LIBS /usr/lib/textreadmode.o"
|
LIBS="$LIBS /usr/lib/textreadmode.o"
|
||||||
AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin])
|
AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin])
|
||||||
AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()])
|
AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()])
|
||||||
|
AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
|
||||||
|
[Define to disable UID restoration test])
|
||||||
AC_DEFINE([DISABLE_SHADOW], [1],
|
AC_DEFINE([DISABLE_SHADOW], [1],
|
||||||
[Define if you want to disable shadow passwords])
|
[Define if you want to disable shadow passwords])
|
||||||
AC_DEFINE([NO_X11_UNIX_SOCKETS], [1],
|
AC_DEFINE([NO_X11_UNIX_SOCKETS], [1],
|
||||||
@ -889,13 +896,18 @@ mips-sony-bsd|mips-sony-newsos4)
|
|||||||
else
|
else
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
fi
|
fi
|
||||||
|
AC_CHECK_FUNC([setppriv],
|
||||||
|
[ AC_CHECK_HEADERS([priv.h], [
|
||||||
|
SOLARIS_PRIVS="yes"
|
||||||
|
])
|
||||||
|
])
|
||||||
AC_ARG_WITH([solaris-contracts],
|
AC_ARG_WITH([solaris-contracts],
|
||||||
[ --with-solaris-contracts Enable Solaris process contracts (experimental)],
|
[ --with-solaris-contracts Enable Solaris process contracts (experimental)],
|
||||||
[
|
[
|
||||||
AC_CHECK_LIB([contract], [ct_tmpl_activate],
|
AC_CHECK_LIB([contract], [ct_tmpl_activate],
|
||||||
[ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1],
|
[ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1],
|
||||||
[Define if you have Solaris process contracts])
|
[Define if you have Solaris process contracts])
|
||||||
SSHDLIBS="$SSHDLIBS -lcontract"
|
LIBS="$LIBS -lcontract"
|
||||||
SPC_MSG="yes" ], )
|
SPC_MSG="yes" ], )
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -905,10 +917,27 @@ mips-sony-bsd|mips-sony-newsos4)
|
|||||||
AC_CHECK_LIB([project], [setproject],
|
AC_CHECK_LIB([project], [setproject],
|
||||||
[ AC_DEFINE([USE_SOLARIS_PROJECTS], [1],
|
[ AC_DEFINE([USE_SOLARIS_PROJECTS], [1],
|
||||||
[Define if you have Solaris projects])
|
[Define if you have Solaris projects])
|
||||||
SSHDLIBS="$SSHDLIBS -lproject"
|
LIBS="$LIBS -lproject"
|
||||||
SP_MSG="yes" ], )
|
SP_MSG="yes" ], )
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
AC_ARG_WITH([solaris-privs],
|
||||||
|
[ --with-solaris-privs Enable Solaris/Illumos privileges (experimental)],
|
||||||
|
[
|
||||||
|
AC_MSG_CHECKING([for Solaris/Illumos privilege support])
|
||||||
|
if test "x$SOLARIS_PRIVS" = "xyes" ; then
|
||||||
|
AC_MSG_RESULT([found])
|
||||||
|
AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
|
||||||
|
[Define to disable UID restoration test])
|
||||||
|
AC_DEFINE([USE_SOLARIS_PRIVS], [1],
|
||||||
|
[Define if you have Solaris privileges])
|
||||||
|
SPP_MSG="yes"
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([not found])
|
||||||
|
AC_MSG_ERROR([*** must have support for Solaris privileges to use --with-solaris-privs])
|
||||||
|
fi
|
||||||
|
],
|
||||||
|
)
|
||||||
TEST_SHELL=$SHELL # let configure find us a capable shell
|
TEST_SHELL=$SHELL # let configure find us a capable shell
|
||||||
;;
|
;;
|
||||||
*-*-sunos4*)
|
*-*-sunos4*)
|
||||||
@ -3156,6 +3185,10 @@ elif test "x$sandbox_arg" = "xrlimit" || \
|
|||||||
AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit])
|
AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit])
|
||||||
SANDBOX_STYLE="rlimit"
|
SANDBOX_STYLE="rlimit"
|
||||||
AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)])
|
AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)])
|
||||||
|
elif test "x$sandbox_arg" = "xsolaris" || \
|
||||||
|
( test -z "$sandbox_arg" && test "x$SOLARIS_PRIVS" = "xyes" ) ; then
|
||||||
|
SANDBOX_STYLE="solaris"
|
||||||
|
AC_DEFINE([SANDBOX_SOLARIS], [1], [Sandbox using Solaris/Illumos privileges])
|
||||||
elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
|
elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
|
||||||
test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
|
test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
|
||||||
SANDBOX_STYLE="none"
|
SANDBOX_STYLE="none"
|
||||||
@ -4945,6 +4978,7 @@ echo " MD5 password support: $MD5_MSG"
|
|||||||
echo " libedit support: $LIBEDIT_MSG"
|
echo " libedit support: $LIBEDIT_MSG"
|
||||||
echo " Solaris process contract support: $SPC_MSG"
|
echo " Solaris process contract support: $SPC_MSG"
|
||||||
echo " Solaris project support: $SP_MSG"
|
echo " Solaris project support: $SP_MSG"
|
||||||
|
echo " Solaris privilege support: $SPP_MSG"
|
||||||
echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
|
echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
|
||||||
echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
|
echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
|
||||||
echo " BSD Auth support: $BSD_AUTH_MSG"
|
echo " BSD Auth support: $BSD_AUTH_MSG"
|
||||||
|
2
mux.c
2
mux.c
@ -1891,6 +1891,7 @@ mux_client_request_session(int fd)
|
|||||||
|
|
||||||
if (pledge("stdio proc tty", NULL) == -1)
|
if (pledge("stdio proc tty", NULL) == -1)
|
||||||
fatal("%s pledge(): %s", __func__, strerror(errno));
|
fatal("%s pledge(): %s", __func__, strerror(errno));
|
||||||
|
platform_pledge_mux();
|
||||||
|
|
||||||
signal(SIGHUP, control_client_sighandler);
|
signal(SIGHUP, control_client_sighandler);
|
||||||
signal(SIGINT, control_client_sighandler);
|
signal(SIGINT, control_client_sighandler);
|
||||||
@ -2001,6 +2002,7 @@ mux_client_request_stdio_fwd(int fd)
|
|||||||
|
|
||||||
if (pledge("stdio proc tty", NULL) == -1)
|
if (pledge("stdio proc tty", NULL) == -1)
|
||||||
fatal("%s pledge(): %s", __func__, strerror(errno));
|
fatal("%s pledge(): %s", __func__, strerror(errno));
|
||||||
|
platform_pledge_mux();
|
||||||
|
|
||||||
debug3("%s: stdio forward request sent", __func__);
|
debug3("%s: stdio forward request sent", __func__);
|
||||||
|
|
||||||
|
@ -227,3 +227,117 @@ solaris_set_default_project(struct passwd *pw)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* USE_SOLARIS_PROJECTS */
|
#endif /* USE_SOLARIS_PROJECTS */
|
||||||
|
|
||||||
|
#ifdef USE_SOLARIS_PRIVS
|
||||||
|
# ifdef HAVE_PRIV_H
|
||||||
|
# include <priv.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
void
|
||||||
|
solaris_drop_privs_pinfo_net_fork_exec(void)
|
||||||
|
{
|
||||||
|
priv_set_t *pset = NULL, *npset = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: this variant avoids dropping DAC filesystem rights, in case
|
||||||
|
* the process calling it is running as root and should have the
|
||||||
|
* ability to read/write/chown any file on the system.
|
||||||
|
*
|
||||||
|
* We start with the basic set, then *add* the DAC rights to it while
|
||||||
|
* taking away other parts of BASIC we don't need. Then we intersect
|
||||||
|
* this with our existing PERMITTED set. In this way we keep any
|
||||||
|
* DAC rights we had before, while otherwise reducing ourselves to
|
||||||
|
* the minimum set of privileges we need to proceed.
|
||||||
|
*
|
||||||
|
* This also means we drop any other parts of "root" that we don't
|
||||||
|
* need (e.g. the ability to kill any process, create new device nodes
|
||||||
|
* etc etc).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((pset = priv_allocset()) == NULL ||
|
||||||
|
(npset = priv_allocset()) == NULL)
|
||||||
|
fatal("priv_allocset: %s", strerror(errno));
|
||||||
|
|
||||||
|
priv_basicset(npset);
|
||||||
|
|
||||||
|
if (priv_addset(npset, PRIV_FILE_CHOWN) != 0 ||
|
||||||
|
priv_addset(npset, PRIV_FILE_DAC_READ) != 0 ||
|
||||||
|
priv_addset(npset, PRIV_FILE_DAC_SEARCH) != 0 ||
|
||||||
|
priv_addset(npset, PRIV_FILE_DAC_WRITE) != 0 ||
|
||||||
|
priv_addset(npset, PRIV_FILE_OWNER) != 0)
|
||||||
|
fatal("priv_addset: %s", strerror(errno));
|
||||||
|
|
||||||
|
if (priv_delset(npset, PRIV_FILE_LINK_ANY) != 0 ||
|
||||||
|
priv_delset(npset, PRIV_NET_ACCESS) != 0 ||
|
||||||
|
priv_delset(npset, PRIV_PROC_EXEC) != 0 ||
|
||||||
|
priv_delset(npset, PRIV_PROC_FORK) != 0 ||
|
||||||
|
priv_delset(npset, PRIV_PROC_INFO) != 0 ||
|
||||||
|
priv_delset(npset, PRIV_PROC_SESSION) != 0)
|
||||||
|
fatal("priv_delset: %s", strerror(errno));
|
||||||
|
|
||||||
|
if (getppriv(PRIV_PERMITTED, pset) != 0)
|
||||||
|
fatal("getppriv: %s", strerror(errno));
|
||||||
|
|
||||||
|
priv_intersect(pset, npset);
|
||||||
|
|
||||||
|
if (setppriv(PRIV_SET, PRIV_PERMITTED, npset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_INHERITABLE, npset) != 0)
|
||||||
|
fatal("setppriv: %s", strerror(errno));
|
||||||
|
|
||||||
|
priv_freeset(pset);
|
||||||
|
priv_freeset(npset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
solaris_drop_privs_root_pinfo_net(void)
|
||||||
|
{
|
||||||
|
priv_set_t *pset = NULL;
|
||||||
|
|
||||||
|
if ((pset = priv_allocset()) == NULL)
|
||||||
|
fatal("priv_allocset: %s", strerror(errno));
|
||||||
|
|
||||||
|
/* Start with "basic" and drop everything we don't need. */
|
||||||
|
priv_basicset(pset);
|
||||||
|
|
||||||
|
if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_PROC_INFO) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_PROC_SESSION) != 0)
|
||||||
|
fatal("priv_delset: %s", strerror(errno));
|
||||||
|
|
||||||
|
if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
|
||||||
|
fatal("setppriv: %s", strerror(errno));
|
||||||
|
|
||||||
|
priv_freeset(pset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
solaris_drop_privs_root_pinfo_net_exec(void)
|
||||||
|
{
|
||||||
|
priv_set_t *pset = NULL;
|
||||||
|
|
||||||
|
if ((pset = priv_allocset()) == NULL)
|
||||||
|
fatal("priv_allocset: %s", strerror(errno));
|
||||||
|
|
||||||
|
/* Start with "basic" and drop everything we don't need. */
|
||||||
|
priv_basicset(pset);
|
||||||
|
|
||||||
|
if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_PROC_EXEC) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_PROC_INFO) != 0 ||
|
||||||
|
priv_delset(pset, PRIV_PROC_SESSION) != 0)
|
||||||
|
fatal("priv_delset: %s", strerror(errno));
|
||||||
|
|
||||||
|
if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
|
||||||
|
fatal("setppriv: %s", strerror(errno));
|
||||||
|
|
||||||
|
priv_freeset(pset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -26,5 +26,8 @@ void solaris_contract_pre_fork(void);
|
|||||||
void solaris_contract_post_fork_child(void);
|
void solaris_contract_post_fork_child(void);
|
||||||
void solaris_contract_post_fork_parent(pid_t pid);
|
void solaris_contract_post_fork_parent(pid_t pid);
|
||||||
void solaris_set_default_project(struct passwd *);
|
void solaris_set_default_project(struct passwd *);
|
||||||
|
void solaris_drop_privs_pinfo_net_fork_exec(void);
|
||||||
|
void solaris_drop_privs_root_pinfo_net(void);
|
||||||
|
void solaris_drop_privs_root_pinfo_net_exec(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
71
platform-pledge.c
Normal file
71
platform-pledge.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Joyent, Inc
|
||||||
|
* Author: Alex Wilson <alex.wilson@joyent.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "openbsd-compat/openbsd-compat.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop any fine-grained privileges that are not needed for post-startup
|
||||||
|
* operation of ssh-agent
|
||||||
|
*
|
||||||
|
* Should be as close as possible to pledge("stdio cpath unix id proc exec", ...)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
platform_pledge_agent(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_SOLARIS_PRIVS
|
||||||
|
/*
|
||||||
|
* Note: Solaris priv dropping is closer to tame() than pledge(), but
|
||||||
|
* we will use what we have.
|
||||||
|
*/
|
||||||
|
solaris_drop_privs_root_pinfo_net();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop any fine-grained privileges that are not needed for post-startup
|
||||||
|
* operation of sftp-server
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
platform_pledge_sftp_server(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_SOLARIS_PRIVS
|
||||||
|
solaris_drop_privs_pinfo_net_fork_exec();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop any fine-grained privileges that are not needed for the post-startup
|
||||||
|
* operation of the SSH client mux
|
||||||
|
*
|
||||||
|
* Should be as close as possible to pledge("stdio proc tty", ...)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
platform_pledge_mux(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_SOLARIS_PRIVS
|
||||||
|
solaris_drop_privs_root_pinfo_net_exec();
|
||||||
|
#endif
|
||||||
|
}
|
@ -31,3 +31,8 @@ void platform_setusercontext_post_groups(struct passwd *);
|
|||||||
char *platform_get_krb5_client(const char *);
|
char *platform_get_krb5_client(const char *);
|
||||||
char *platform_krb5_get_principal_name(const char *);
|
char *platform_krb5_get_principal_name(const char *);
|
||||||
int platform_sys_dir_uid(uid_t);
|
int platform_sys_dir_uid(uid_t);
|
||||||
|
|
||||||
|
/* in platform-pledge.c */
|
||||||
|
void platform_pledge_agent(void);
|
||||||
|
void platform_pledge_sftp_server(void);
|
||||||
|
void platform_pledge_mux(void);
|
||||||
|
107
sandbox-solaris.c
Normal file
107
sandbox-solaris.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Joyent, Inc
|
||||||
|
* Author: Alex Wilson <alex.wilson@joyent.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#ifdef SANDBOX_SOLARIS
|
||||||
|
#ifndef USE_SOLARIS_PRIVS
|
||||||
|
# error "--with-solaris-privs must be used with the Solaris sandbox"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#ifdef HAVE_PRIV_H
|
||||||
|
# include <priv.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "ssh-sandbox.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
struct ssh_sandbox {
|
||||||
|
priv_set_t *pset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssh_sandbox *
|
||||||
|
ssh_sandbox_init(struct monitor *monitor)
|
||||||
|
{
|
||||||
|
struct ssh_sandbox *box = NULL;
|
||||||
|
|
||||||
|
box = xcalloc(1, sizeof(*box));
|
||||||
|
box->pset = priv_allocset();
|
||||||
|
|
||||||
|
if (box->pset == NULL) {
|
||||||
|
free(box);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start with "basic" and drop everything we don't need. */
|
||||||
|
priv_basicset(box->pset);
|
||||||
|
|
||||||
|
/* Drop everything except the ability to use already-opened files */
|
||||||
|
if (priv_delset(box->pset, PRIV_FILE_LINK_ANY) != 0 ||
|
||||||
|
priv_delset(box->pset, PRIV_NET_ACCESS) != 0 ||
|
||||||
|
priv_delset(box->pset, PRIV_PROC_EXEC) != 0 ||
|
||||||
|
priv_delset(box->pset, PRIV_PROC_FORK) != 0 ||
|
||||||
|
priv_delset(box->pset, PRIV_PROC_INFO) != 0 ||
|
||||||
|
priv_delset(box->pset, PRIV_PROC_SESSION) != 0) {
|
||||||
|
free(box);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* These may not be available on older Solaris-es */
|
||||||
|
# if defined(PRIV_FILE_READ) && defined(PRIV_FILE_WRITE)
|
||||||
|
if (priv_delset(box->pset, PRIV_FILE_READ) != 0 ||
|
||||||
|
priv_delset(box->pset, PRIV_FILE_WRITE) != 0) {
|
||||||
|
free(box);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ssh_sandbox_child(struct ssh_sandbox *box)
|
||||||
|
{
|
||||||
|
if (setppriv(PRIV_SET, PRIV_PERMITTED, box->pset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_LIMIT, box->pset) != 0 ||
|
||||||
|
setppriv(PRIV_SET, PRIV_INHERITABLE, box->pset) != 0)
|
||||||
|
fatal("setppriv: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ssh_sandbox_parent_finish(struct ssh_sandbox *box)
|
||||||
|
{
|
||||||
|
priv_freeset(box->pset);
|
||||||
|
box->pset = NULL;
|
||||||
|
free(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
|
||||||
|
{
|
||||||
|
/* Nothing to do here */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SANDBOX_SOLARIS */
|
@ -1598,6 +1598,9 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
|
|||||||
fatal("unable to make the process undumpable");
|
fatal("unable to make the process undumpable");
|
||||||
#endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */
|
#endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */
|
||||||
|
|
||||||
|
/* Drop any fine-grained privileges we don't need */
|
||||||
|
platform_pledge_sftp_server();
|
||||||
|
|
||||||
if ((cp = getenv("SSH_CONNECTION")) != NULL) {
|
if ((cp = getenv("SSH_CONNECTION")) != NULL) {
|
||||||
client_addr = xstrdup(cp);
|
client_addr = xstrdup(cp);
|
||||||
if ((cp = strchr(client_addr, ' ')) == NULL) {
|
if ((cp = strchr(client_addr, ' ')) == NULL) {
|
||||||
|
@ -1417,6 +1417,7 @@ skip:
|
|||||||
|
|
||||||
if (pledge("stdio cpath unix id proc exec", NULL) == -1)
|
if (pledge("stdio cpath unix id proc exec", NULL) == -1)
|
||||||
fatal("%s: pledge: %s", __progname, strerror(errno));
|
fatal("%s: pledge: %s", __progname, strerror(errno));
|
||||||
|
platform_pledge_agent();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
|
prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
|
||||||
|
18
uidswap.c
18
uidswap.c
@ -134,7 +134,7 @@ temporarily_use_uid(struct passwd *pw)
|
|||||||
void
|
void
|
||||||
permanently_drop_suid(uid_t uid)
|
permanently_drop_suid(uid_t uid)
|
||||||
{
|
{
|
||||||
#ifndef HAVE_CYGWIN
|
#ifndef NO_UID_RESTORATION_TEST
|
||||||
uid_t old_uid = getuid();
|
uid_t old_uid = getuid();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -142,8 +142,14 @@ permanently_drop_suid(uid_t uid)
|
|||||||
if (setresuid(uid, uid, uid) < 0)
|
if (setresuid(uid, uid, uid) < 0)
|
||||||
fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));
|
fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));
|
||||||
|
|
||||||
#ifndef HAVE_CYGWIN
|
#ifndef NO_UID_RESTORATION_TEST
|
||||||
/* Try restoration of UID if changed (test clearing of saved uid) */
|
/*
|
||||||
|
* Try restoration of UID if changed (test clearing of saved uid).
|
||||||
|
*
|
||||||
|
* Note that we don't do this on Cygwin, or on Solaris-based platforms
|
||||||
|
* where fine-grained privileges are available (the user might be
|
||||||
|
* deliberately allowed the right to setuid back to root).
|
||||||
|
*/
|
||||||
if (old_uid != uid &&
|
if (old_uid != uid &&
|
||||||
(setuid(old_uid) != -1 || seteuid(old_uid) != -1))
|
(setuid(old_uid) != -1 || seteuid(old_uid) != -1))
|
||||||
fatal("%s: was able to restore old [e]uid", __func__);
|
fatal("%s: was able to restore old [e]uid", __func__);
|
||||||
@ -199,7 +205,7 @@ restore_uid(void)
|
|||||||
void
|
void
|
||||||
permanently_set_uid(struct passwd *pw)
|
permanently_set_uid(struct passwd *pw)
|
||||||
{
|
{
|
||||||
#ifndef HAVE_CYGWIN
|
#ifndef NO_UID_RESTORATION_TEST
|
||||||
uid_t old_uid = getuid();
|
uid_t old_uid = getuid();
|
||||||
gid_t old_gid = getgid();
|
gid_t old_gid = getgid();
|
||||||
#endif
|
#endif
|
||||||
@ -227,7 +233,7 @@ permanently_set_uid(struct passwd *pw)
|
|||||||
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
|
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
|
||||||
fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
|
fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
|
||||||
|
|
||||||
#ifndef HAVE_CYGWIN
|
#ifndef NO_UID_RESTORATION_TEST
|
||||||
/* Try restoration of GID if changed (test clearing of saved gid) */
|
/* Try restoration of GID if changed (test clearing of saved gid) */
|
||||||
if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
|
if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
|
||||||
(setgid(old_gid) != -1 || setegid(old_gid) != -1))
|
(setgid(old_gid) != -1 || setegid(old_gid) != -1))
|
||||||
@ -241,7 +247,7 @@ permanently_set_uid(struct passwd *pw)
|
|||||||
(u_int)pw->pw_gid);
|
(u_int)pw->pw_gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_CYGWIN
|
#ifndef NO_UID_RESTORATION_TEST
|
||||||
/* Try restoration of UID if changed (test clearing of saved uid) */
|
/* Try restoration of UID if changed (test clearing of saved uid) */
|
||||||
if (old_uid != pw->pw_uid &&
|
if (old_uid != pw->pw_uid &&
|
||||||
(setuid(old_uid) != -1 || seteuid(old_uid) != -1))
|
(setuid(old_uid) != -1 || seteuid(old_uid) != -1))
|
||||||
|
Loading…
Reference in New Issue
Block a user