diff --git a/configure.ac b/configure.ac index aeef42a..d01e67e 100644 --- a/configure.ac +++ b/configure.ac @@ -4998,6 +4998,37 @@ if test -n "$conf_lastlog_location"; then [Define if you want to specify the path to your lastlog file]) fi +AC_ARG_WITH(libcap-ng, + [ --with-libcap-ng=[auto/yes/no] Add Libcap-ng support [default=auto]],, + with_libcap_ng=auto) + +dnl libcap-ng detection +if test x$with_libcap_ng = xno ; then + have_libcap_ng=no; +else + # Start by checking for header file + AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no) + + # See if we have libcap-ng library + AC_CHECK_LIB(cap-ng, capng_clear, CAPNG_LDADD=-lcap-ng,) + + # Check results are usable + if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then + AC_MSG_ERROR(libcap-ng support was requested and the library was not found) + fi + if test x$CAPNG_LDADD != x -a $capng_headers = no ; then + AC_MSG_ERROR(libcap-ng libraries found but headers are missing) + fi +fi +AC_MSG_CHECKING(whether to use libcap-ng) +if test x$CAPNG_LDADD != x ; then + AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support]) + SSHDLIBS="$SSHDLIBS -lcap-ng" + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + dnl utmp detection AC_MSG_CHECKING([if your system defines UTMP_FILE]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/session.c b/session.c index 6cfcba4..80d2806 100644 --- a/session.c +++ b/session.c @@ -96,6 +96,10 @@ #include "monitor_wrap.h" #include "sftp.h" +#ifdef HAVE_LIBCAP_NG +#include +#endif + #if defined(KRB5) && defined(USE_AFS) #include #endif @@ -1586,6 +1590,7 @@ void do_setusercontext(struct passwd *pw) { char *chroot_path, *tmp; + int dropped_suid = -1; platform_setusercontext(pw); @@ -1619,10 +1624,25 @@ do_setusercontext(struct passwd *pw) pw->pw_uid); chroot_path = percent_expand(tmp, "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL); +#ifdef HAVE_LIBCAP_NG + /* drop suid soon, retain SYS_CHROOT capability */ + capng_clear(CAPNG_SELECT_BOTH); + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SYS_CHROOT); + if (pw->pw_uid != 0 && + (dropped_suid = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_INIT_SUPP_GRP)) != 0) + logit("capng_change_id() = %d (failure): Try to drop UID later", dropped_suid); +#endif #ifdef WITH_SELINUX sshd_selinux_copy_context(); #endif safely_chroot(chroot_path, pw->pw_uid); +#ifdef HAVE_LIBCAP_NG + /* Drop chroot capability. Already used */ + if (dropped_suid == 0) { + capng_clear(CAPNG_SELECT_BOTH); + capng_apply(CAPNG_SELECT_BOTH); + } +#endif free(tmp); free(chroot_path); /* Make sure we don't attempt to chroot again */ @@ -1654,8 +1673,9 @@ do_setusercontext(struct passwd *pw) if (!in_chroot && set_id(pw->pw_name) != 0) fatal("set_id(%s) Failed", pw->pw_name); # endif /* USE_LIBIAF */ - /* Permanently switch to the desired uid. */ - permanently_set_uid(pw); + /* Permanently switch to the desired uid if not yet done. */ + if (dropped_suid != 0) + permanently_set_uid(pw); #endif #ifdef WITH_SELINUX