1 From b09b8dcdda058d6f237baf50810f13e5b6aa47bb Mon Sep 17 00:00:00 2001
   2 From: Damien Miller <djm@mindrot.org>
   3 Date: Fri, 8 Jan 2016 14:24:56 +1100
   4 Subject: [PATCH 02/36] Support Illumos/Solaris fine-grained privileges
   5 
   6 Includes a pre-auth privsep sandbox and several pledge()
   7 emulations. bz#2511, patch by Alex Wilson.
   8 
   9 ok dtucker@
  10 ---
  11  Makefile.in                   |   5 +-
  12  configure.ac                  |  38 +++++++++++++-
  13  mux.c                         |   4 ++
  14  openbsd-compat/port-solaris.c | 114 ++++++++++++++++++++++++++++++++++++++++++
  15  openbsd-compat/port-solaris.h |   3 ++
  16  platform-pledge.c             |  71 ++++++++++++++++++++++++++
  17  platform.h                    |   5 ++
  18  sandbox-solaris.c             | 107 +++++++++++++++++++++++++++++++++++++++
  19  sftp-server.c                 |   3 ++
  20  ssh-agent.c                   |   2 +
  21  uidswap.c                     |  18 ++++---
  22  11 files changed, 360 insertions(+), 10 deletions(-)
  23  create mode 100644 platform-pledge.c
  24  create mode 100644 sandbox-solaris.c
  25 
  26 diff --git a/Makefile.in b/Makefile.in
  27 index 40cc7aa..8494713 100644
  28 --- a/Makefile.in
  29 +++ b/Makefile.in
  30 @@ -91,7 +91,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
  31         sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
  32         kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
  33         kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
  34 -       kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o
  35 +       kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
  36 +       platform-pledge.o
  37  
  38  SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
  39         sshconnect.o sshconnect1.o sshconnect2.o mux.o \
  40 @@ -110,7 +111,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
  41         sftp-server.o sftp-common.o \
  42         roaming_common.o roaming_serv.o \
  43         sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
  44 -       sandbox-seccomp-filter.o sandbox-capsicum.o
  45 +       sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o
  46  
  47  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
  48  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
  49 diff --git a/configure.ac b/configure.ac
  50 index 9b05c30..b06cede 100644
  51 --- a/configure.ac
  52 +++ b/configure.ac
  53 @@ -469,6 +469,11 @@ AC_CHECK_HEADERS([sys/un.h], [], [], [
  54  SIA_MSG="no"
  55  SPC_MSG="no"
  56  SP_MSG="no"
  57 +SPP_MSG="no"
  58 +
  59 +# Support for Solaris/Illumos privileges (this test is used by both
  60 +# the --with-solaris-privs option and --with-sandbox=solaris).
  61 +SOLARIS_PRIVS="no"
  62  
  63  # Check for some target-specific stuff
  64  case "$host" in
  65 @@ -575,6 +580,8 @@ case "$host" in
  66         LIBS="$LIBS /usr/lib/textreadmode.o"
  67         AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin])
  68         AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()])
  69 +       AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
  70 +               [Define to disable UID restoration test])
  71         AC_DEFINE([DISABLE_SHADOW], [1],
  72                 [Define if you want to disable shadow passwords])
  73         AC_DEFINE([NO_X11_UNIX_SOCKETS], [1],
  74 @@ -889,13 +896,18 @@ mips-sony-bsd|mips-sony-newsos4)
  75         else
  76                 AC_MSG_RESULT([no])
  77         fi
  78 +       AC_CHECK_FUNC([setppriv],
  79 +               [ AC_CHECK_HEADERS([priv.h], [
  80 +                       SOLARIS_PRIVS="yes"
  81 +               ])
  82 +       ])
  83         AC_ARG_WITH([solaris-contracts],
  84                 [  --with-solaris-contracts Enable Solaris process contracts (experimental)],
  85                 [
  86                 AC_CHECK_LIB([contract], [ct_tmpl_activate],
  87                         [ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1],
  88                                 [Define if you have Solaris process contracts])
  89 -                         SSHDLIBS="$SSHDLIBS -lcontract"
  90 +                         LIBS="$LIBS -lcontract"
  91                           SPC_MSG="yes" ], )
  92                 ],
  93         )
  94 @@ -905,10 +917,27 @@ mips-sony-bsd|mips-sony-newsos4)
  95                 AC_CHECK_LIB([project], [setproject],
  96                         [ AC_DEFINE([USE_SOLARIS_PROJECTS], [1],
  97                                 [Define if you have Solaris projects])
  98 -                       SSHDLIBS="$SSHDLIBS -lproject"
  99 +                       LIBS="$LIBS -lproject"
 100                         SP_MSG="yes" ], )
 101                 ],
 102         )
 103 +       AC_ARG_WITH([solaris-privs],
 104 +               [  --with-solaris-privs    Enable Solaris/Illumos privileges (experimental)],
 105 +               [
 106 +               AC_MSG_CHECKING([for Solaris/Illumos privilege support])
 107 +               if test "x$SOLARIS_PRIVS" = "xyes" ; then
 108 +                       AC_MSG_RESULT([found])
 109 +                       AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
 110 +                               [Define to disable UID restoration test])
 111 +                       AC_DEFINE([USE_SOLARIS_PRIVS], [1],
 112 +                               [Define if you have Solaris privileges])
 113 +                       SPP_MSG="yes"
 114 +               else
 115 +                       AC_MSG_RESULT([not found])
 116 +                       AC_MSG_ERROR([*** must have support for Solaris privileges to use --with-solaris-privs])
 117 +               fi
 118 +               ],
 119 +       )
 120         TEST_SHELL=$SHELL       # let configure find us a capable shell
 121         ;;
 122  *-*-sunos4*)
 123 @@ -3147,6 +3176,10 @@ elif test "x$sandbox_arg" = "xrlimit" || \
 124                 AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit])
 125         SANDBOX_STYLE="rlimit"
 126         AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)])
 127 +elif test "x$sandbox_arg" = "xsolaris" || \
 128 +   ( test -z "$sandbox_arg" && test "x$SOLARIS_PRIVS" = "xyes" ) ; then
 129 +       SANDBOX_STYLE="solaris"
 130 +       AC_DEFINE([SANDBOX_SOLARIS], [1], [Sandbox using Solaris/Illumos privileges])
 131  elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
 132       test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
 133         SANDBOX_STYLE="none"
 134 @@ -4933,6 +4966,7 @@ echo "              MD5 password support: $MD5_MSG"
 135  echo "                   libedit support: $LIBEDIT_MSG"
 136  echo "  Solaris process contract support: $SPC_MSG"
 137  echo "           Solaris project support: $SP_MSG"
 138 +echo "         Solaris privilege support: $SPP_MSG"
 139  echo "       IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
 140  echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
 141  echo "                  BSD Auth support: $BSD_AUTH_MSG"
 142 diff --git a/mux.c b/mux.c
 143 index e6136fd..8c2a53a 100644
 144 --- a/mux.c
 145 +++ b/mux.c
 146 @@ -1889,6 +1889,8 @@ mux_client_request_session(int fd)
 147         }
 148         muxclient_request_id++;
 149  
 150 +       platform_pledge_mux();
 151 +
 152         signal(SIGHUP, control_client_sighandler);
 153         signal(SIGINT, control_client_sighandler);
 154         signal(SIGTERM, control_client_sighandler);
 155 @@ -1996,6 +1998,8 @@ mux_client_request_stdio_fwd(int fd)
 156             mm_send_fd(fd, STDOUT_FILENO) == -1)
 157                 fatal("%s: send fds failed", __func__);
 158  
 159 +       platform_pledge_mux();
 160 +
 161         debug3("%s: stdio forward request sent", __func__);
 162  
 163         /* Read their reply */
 164 diff --git a/openbsd-compat/port-solaris.c b/openbsd-compat/port-solaris.c
 165 index 25382f1..962cd16 100644
 166 --- a/openbsd-compat/port-solaris.c
 167 +++ b/openbsd-compat/port-solaris.c
 168 @@ -227,3 +227,117 @@ solaris_set_default_project(struct passwd *pw)
 169         }
 170  }
 171  #endif /* USE_SOLARIS_PROJECTS */
 172 +
 173 +#ifdef USE_SOLARIS_PRIVS
 174 +# ifdef HAVE_PRIV_H
 175 +#  include <priv.h>
 176 +# endif
 177 +
 178 +void
 179 +solaris_drop_privs_pinfo_net_fork_exec(void)
 180 +{
 181 +       priv_set_t *pset = NULL, *npset = NULL;
 182 +
 183 +       /*
 184 +        * Note: this variant avoids dropping DAC filesystem rights, in case
 185 +        * the process calling it is running as root and should have the
 186 +        * ability to read/write/chown any file on the system.
 187 +        *
 188 +        * We start with the basic set, then *add* the DAC rights to it while
 189 +        * taking away other parts of BASIC we don't need. Then we intersect
 190 +        * this with our existing PERMITTED set. In this way we keep any
 191 +        * DAC rights we had before, while otherwise reducing ourselves to
 192 +        * the minimum set of privileges we need to proceed.
 193 +        *
 194 +        * This also means we drop any other parts of "root" that we don't
 195 +        * need (e.g. the ability to kill any process, create new device nodes
 196 +        * etc etc).
 197 +        */
 198 +
 199 +       if ((pset = priv_allocset()) == NULL ||
 200 +           (npset = priv_allocset()) == NULL)
 201 +               fatal("priv_allocset: %s", strerror(errno));
 202 +
 203 +       priv_basicset(npset);
 204 +
 205 +       if (priv_addset(npset, PRIV_FILE_CHOWN) != 0 ||
 206 +           priv_addset(npset, PRIV_FILE_DAC_READ) != 0 ||
 207 +           priv_addset(npset, PRIV_FILE_DAC_SEARCH) != 0 ||
 208 +           priv_addset(npset, PRIV_FILE_DAC_WRITE) != 0 ||
 209 +           priv_addset(npset, PRIV_FILE_OWNER) != 0)
 210 +               fatal("priv_addset: %s", strerror(errno));
 211 +
 212 +       if (priv_delset(npset, PRIV_FILE_LINK_ANY) != 0 ||
 213 +           priv_delset(npset, PRIV_NET_ACCESS) != 0 ||
 214 +           priv_delset(npset, PRIV_PROC_EXEC) != 0 ||
 215 +           priv_delset(npset, PRIV_PROC_FORK) != 0 ||
 216 +           priv_delset(npset, PRIV_PROC_INFO) != 0 ||
 217 +           priv_delset(npset, PRIV_PROC_SESSION) != 0)
 218 +               fatal("priv_delset: %s", strerror(errno));
 219 +
 220 +       if (getppriv(PRIV_PERMITTED, pset) != 0)
 221 +               fatal("getppriv: %s", strerror(errno));
 222 +
 223 +       priv_intersect(pset, npset);
 224 +
 225 +       if (setppriv(PRIV_SET, PRIV_PERMITTED, npset) != 0 ||
 226 +           setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0 ||
 227 +           setppriv(PRIV_SET, PRIV_INHERITABLE, npset) != 0)
 228 +               fatal("setppriv: %s", strerror(errno));
 229 +
 230 +       priv_freeset(pset);
 231 +       priv_freeset(npset);
 232 +}
 233 +
 234 +void
 235 +solaris_drop_privs_root_pinfo_net(void)
 236 +{
 237 +       priv_set_t *pset = NULL;
 238 +
 239 +       if ((pset = priv_allocset()) == NULL)
 240 +               fatal("priv_allocset: %s", strerror(errno));
 241 +
 242 +       /* Start with "basic" and drop everything we don't need. */
 243 +       priv_basicset(pset);
 244 +
 245 +       if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
 246 +           priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
 247 +           priv_delset(pset, PRIV_PROC_INFO) != 0 ||
 248 +           priv_delset(pset, PRIV_PROC_SESSION) != 0)
 249 +               fatal("priv_delset: %s", strerror(errno));
 250 +
 251 +       if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
 252 +           setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
 253 +           setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
 254 +               fatal("setppriv: %s", strerror(errno));
 255 +
 256 +       priv_freeset(pset);
 257 +}
 258 +
 259 +void
 260 +solaris_drop_privs_root_pinfo_net_exec(void)
 261 +{
 262 +       priv_set_t *pset = NULL;
 263 +
 264 +       if ((pset = priv_allocset()) == NULL)
 265 +               fatal("priv_allocset: %s", strerror(errno));
 266 +
 267 +       /* Start with "basic" and drop everything we don't need. */
 268 +       priv_basicset(pset);
 269 +
 270 +       if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
 271 +           priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
 272 +           priv_delset(pset, PRIV_PROC_EXEC) != 0 ||
 273 +           priv_delset(pset, PRIV_PROC_INFO) != 0 ||
 274 +           priv_delset(pset, PRIV_PROC_SESSION) != 0)
 275 +               fatal("priv_delset: %s", strerror(errno));
 276 +
 277 +       if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
 278 +           setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
 279 +           setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
 280 +               fatal("setppriv: %s", strerror(errno));
 281 +
 282 +       priv_freeset(pset);
 283 +}
 284 +
 285 +#endif
 286 diff --git a/openbsd-compat/port-solaris.h b/openbsd-compat/port-solaris.h
 287 index cd442e7..b077e18 100644
 288 --- a/openbsd-compat/port-solaris.h
 289 +++ b/openbsd-compat/port-solaris.h
 290 @@ -26,5 +26,8 @@ void solaris_contract_pre_fork(void);
 291  void solaris_contract_post_fork_child(void);
 292  void solaris_contract_post_fork_parent(pid_t pid);
 293  void solaris_set_default_project(struct passwd *);
 294 +void solaris_drop_privs_pinfo_net_fork_exec(void);
 295 +void solaris_drop_privs_root_pinfo_net(void);
 296 +void solaris_drop_privs_root_pinfo_net_exec(void);
 297  
 298  #endif
 299 diff --git a/platform-pledge.c b/platform-pledge.c
 300 new file mode 100644
 301 index 0000000..4a6ec15
 302 --- /dev/null
 303 +++ b/platform-pledge.c
 304 @@ -0,0 +1,71 @@
 305 +/*
 306 + * Copyright (c) 2015 Joyent, Inc
 307 + * Author: Alex Wilson <alex.wilson@joyent.com>
 308 + *
 309 + * Permission to use, copy, modify, and distribute this software for any
 310 + * purpose with or without fee is hereby granted, provided that the above
 311 + * copyright notice and this permission notice appear in all copies.
 312 + *
 313 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 314 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 315 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 316 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 317 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 318 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 319 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 320 + */
 321 +
 322 +#include "includes.h"
 323 +
 324 +#include <sys/types.h>
 325 +
 326 +#include <stdarg.h>
 327 +#include <unistd.h>
 328 +
 329 +#include "platform.h"
 330 +
 331 +#include "openbsd-compat/openbsd-compat.h"
 332 +
 333 +/*
 334 + * Drop any fine-grained privileges that are not needed for post-startup
 335 + * operation of ssh-agent
 336 + *
 337 + * Should be as close as possible to pledge("stdio cpath unix id proc exec", ...)
 338 + */
 339 +void
 340 +platform_pledge_agent(void)
 341 +{
 342 +#ifdef USE_SOLARIS_PRIVS
 343 +       /*
 344 +        * Note: Solaris priv dropping is closer to tame() than pledge(), but
 345 +        * we will use what we have.
 346 +        */
 347 +       solaris_drop_privs_root_pinfo_net();
 348 +#endif
 349 +}
 350 +
 351 +/*
 352 + * Drop any fine-grained privileges that are not needed for post-startup
 353 + * operation of sftp-server
 354 + */
 355 +void
 356 +platform_pledge_sftp_server(void)
 357 +{
 358 +#ifdef USE_SOLARIS_PRIVS
 359 +       solaris_drop_privs_pinfo_net_fork_exec();
 360 +#endif
 361 +}
 362 +
 363 +/*
 364 + * Drop any fine-grained privileges that are not needed for the post-startup
 365 + * operation of the SSH client mux
 366 + *
 367 + * Should be as close as possible to pledge("stdio proc tty", ...)
 368 + */
 369 +void
 370 +platform_pledge_mux(void)
 371 +{
 372 +#ifdef USE_SOLARIS_PRIVS
 373 +       solaris_drop_privs_root_pinfo_net_exec();
 374 +#endif
 375 +}
 376 diff --git a/platform.h b/platform.h
 377 index 1c7a45d..e687c99 100644
 378 --- a/platform.h
 379 +++ b/platform.h
 380 @@ -31,3 +31,8 @@ void platform_setusercontext_post_groups(struct passwd *);
 381  char *platform_get_krb5_client(const char *);
 382  char *platform_krb5_get_principal_name(const char *);
 383  int platform_sys_dir_uid(uid_t);
 384 +
 385 +/* in platform-pledge.c */
 386 +void platform_pledge_agent(void);
 387 +void platform_pledge_sftp_server(void);
 388 +void platform_pledge_mux(void);
 389 diff --git a/sandbox-solaris.c b/sandbox-solaris.c
 390 new file mode 100644
 391 index 0000000..98714e1
 392 --- /dev/null
 393 +++ b/sandbox-solaris.c
 394 @@ -0,0 +1,107 @@
 395 +/*
 396 + * Copyright (c) 2015 Joyent, Inc
 397 + * Author: Alex Wilson <alex.wilson@joyent.com>
 398 + *
 399 + * Permission to use, copy, modify, and distribute this software for any
 400 + * purpose with or without fee is hereby granted, provided that the above
 401 + * copyright notice and this permission notice appear in all copies.
 402 + *
 403 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 404 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 405 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 406 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 407 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 408 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 409 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 410 + */
 411 +
 412 +#include "includes.h"
 413 +
 414 +#ifdef SANDBOX_SOLARIS
 415 +#ifndef USE_SOLARIS_PRIVS
 416 +# error "--with-solaris-privs must be used with the Solaris sandbox"
 417 +#endif
 418 +
 419 +#include <sys/types.h>
 420 +
 421 +#include <errno.h>
 422 +#include <stdarg.h>
 423 +#include <stdio.h>
 424 +#include <stdlib.h>
 425 +#include <string.h>
 426 +#include <unistd.h>
 427 +#ifdef HAVE_PRIV_H
 428 +# include <priv.h>
 429 +#endif
 430 +
 431 +#include "log.h"
 432 +#include "ssh-sandbox.h"
 433 +#include "xmalloc.h"
 434 +
 435 +struct ssh_sandbox {
 436 +       priv_set_t *pset;
 437 +};
 438 +
 439 +struct ssh_sandbox *
 440 +ssh_sandbox_init(struct monitor *monitor)
 441 +{
 442 +       struct ssh_sandbox *box = NULL;
 443 +
 444 +       box = xcalloc(1, sizeof(*box));
 445 +       box->pset = priv_allocset();
 446 +
 447 +       if (box->pset == NULL) {
 448 +               free(box);
 449 +               return NULL;
 450 +       }
 451 +
 452 +       /* Start with "basic" and drop everything we don't need. */
 453 +       priv_basicset(box->pset);
 454 +
 455 +       /* Drop everything except the ability to use already-opened files */
 456 +       if (priv_delset(box->pset, PRIV_FILE_LINK_ANY) != 0 ||
 457 +           priv_delset(box->pset, PRIV_NET_ACCESS) != 0 ||
 458 +           priv_delset(box->pset, PRIV_PROC_EXEC) != 0 ||
 459 +           priv_delset(box->pset, PRIV_PROC_FORK) != 0 ||
 460 +           priv_delset(box->pset, PRIV_PROC_INFO) != 0 ||
 461 +           priv_delset(box->pset, PRIV_PROC_SESSION) != 0) {
 462 +               free(box);
 463 +               return NULL;
 464 +       }
 465 +
 466 +       /* These may not be available on older Solaris-es */
 467 +# if defined(PRIV_FILE_READ) && defined(PRIV_FILE_WRITE)
 468 +       if (priv_delset(box->pset, PRIV_FILE_READ) != 0 ||
 469 +           priv_delset(box->pset, PRIV_FILE_WRITE) != 0) {
 470 +               free(box);
 471 +               return NULL;
 472 +       }
 473 +# endif
 474 +
 475 +       return box;
 476 +}
 477 +
 478 +void
 479 +ssh_sandbox_child(struct ssh_sandbox *box)
 480 +{
 481 +       if (setppriv(PRIV_SET, PRIV_PERMITTED, box->pset) != 0 ||
 482 +           setppriv(PRIV_SET, PRIV_LIMIT, box->pset) != 0 ||
 483 +           setppriv(PRIV_SET, PRIV_INHERITABLE, box->pset) != 0)
 484 +               fatal("setppriv: %s", strerror(errno));
 485 +}
 486 +
 487 +void
 488 +ssh_sandbox_parent_finish(struct ssh_sandbox *box)
 489 +{
 490 +       priv_freeset(box->pset);
 491 +       box->pset = NULL;
 492 +       free(box);
 493 +}
 494 +
 495 +void
 496 +ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
 497 +{
 498 +       /* Nothing to do here */
 499 +}
 500 +
 501 +#endif /* SANDBOX_SOLARIS */
 502 diff --git a/sftp-server.c b/sftp-server.c
 503 index eac11d7..3877c03 100644
 504 --- a/sftp-server.c
 505 +++ b/sftp-server.c
 506 @@ -1598,6 +1598,9 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
 507                 fatal("unable to make the process undumpable");
 508  #endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */
 509  
 510 +       /* Drop any fine-grained privileges we don't need */
 511 +       platform_pledge_sftp_server();
 512 +
 513         if ((cp = getenv("SSH_CONNECTION")) != NULL) {
 514                 client_addr = xstrdup(cp);
 515                 if ((cp = strchr(client_addr, ' ')) == NULL) {
 516 diff --git a/ssh-agent.c b/ssh-agent.c
 517 index a335ea3..6c2f6d5 100644
 518 --- a/ssh-agent.c
 519 +++ b/ssh-agent.c
 520 @@ -1402,6 +1402,8 @@ skip:
 521         signal(SIGTERM, cleanup_handler);
 522         nalloc = 0;
 523  
 524 +       platform_pledge_agent();
 525 +
 526         while (1) {
 527                 prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
 528                 result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
 529 diff --git a/uidswap.c b/uidswap.c
 530 index 0702e1d..8bf6b24 100644
 531 --- a/uidswap.c
 532 +++ b/uidswap.c
 533 @@ -134,7 +134,7 @@ temporarily_use_uid(struct passwd *pw)
 534  void
 535  permanently_drop_suid(uid_t uid)
 536  {
 537 -#ifndef HAVE_CYGWIN
 538 +#ifndef NO_UID_RESTORATION_TEST
 539         uid_t old_uid = getuid();
 540  #endif
 541  
 542 @@ -142,8 +142,14 @@ permanently_drop_suid(uid_t uid)
 543         if (setresuid(uid, uid, uid) < 0)
 544                 fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));
 545  
 546 -#ifndef HAVE_CYGWIN
 547 -       /* Try restoration of UID if changed (test clearing of saved uid) */
 548 +#ifndef NO_UID_RESTORATION_TEST
 549 +       /*
 550 +        * Try restoration of UID if changed (test clearing of saved uid).
 551 +        *
 552 +        * Note that we don't do this on Cygwin, or on Solaris-based platforms
 553 +        * where fine-grained privileges are available (the user might be
 554 +        * deliberately allowed the right to setuid back to root).
 555 +        */
 556         if (old_uid != uid &&
 557             (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
 558                 fatal("%s: was able to restore old [e]uid", __func__);
 559 @@ -199,7 +205,7 @@ restore_uid(void)
 560  void
 561  permanently_set_uid(struct passwd *pw)
 562  {
 563 -#ifndef HAVE_CYGWIN
 564 +#ifndef NO_UID_RESTORATION_TEST
 565         uid_t old_uid = getuid();
 566         gid_t old_gid = getgid();
 567  #endif
 568 @@ -227,7 +233,7 @@ permanently_set_uid(struct passwd *pw)
 569         if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
 570                 fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
 571  
 572 -#ifndef HAVE_CYGWIN
 573 +#ifndef NO_UID_RESTORATION_TEST
 574         /* Try restoration of GID if changed (test clearing of saved gid) */
 575         if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
 576             (setgid(old_gid) != -1 || setegid(old_gid) != -1))
 577 @@ -241,7 +247,7 @@ permanently_set_uid(struct passwd *pw)
 578                     (u_int)pw->pw_gid);
 579         }
 580  
 581 -#ifndef HAVE_CYGWIN
 582 +#ifndef NO_UID_RESTORATION_TEST
 583         /* Try restoration of UID if changed (test clearing of saved uid) */
 584         if (old_uid != pw->pw_uid &&
 585             (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
 586 -- 
 587 2.5.4 (Apple Git-61)
 588