From bb6a9cabe374da9f09fa0983a059d1fc3c6b3ed7 Mon Sep 17 00:00:00 2001 From: Eric Keller Date: Fri, 15 Feb 2013 14:12:29 +0100 Subject: [PATCH 1/3] update Makefile.in and configure.in and config.h.in to support PAM ./configure --with-pam make --- Makefile.in | 4 ++-- config.h.in | 6 ++++++ configure.in | 20 +++++++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index e2dd002..41847ed 100644 --- a/Makefile.in +++ b/Makefile.in @@ -13,7 +13,7 @@ INSTALL_MAN = $(INSTALL_PREFIX)/share/man MISSING_SOURCES = @LOCAL_MISSING_SOURCES@ MISSING_OBJECTS = $(MISSING_SOURCES:.c=.o) CC = @CC@ - +PAM_LIBS = @PAM_LIBS@ .PHONY: all psman install clean distclean .c.o: @@ -22,7 +22,7 @@ CC = @CC@ all: daemonize daemonize: daemonize.o getopt.o $(MISSING_OBJECTS) - $(CC) $(CFLAGS) -o daemonize daemonize.o getopt.o $(MISSING_OBJECTS) + $(CC) $(CFLAGS) -o daemonize daemonize.o getopt.o $(MISSING_OBJECTS) $(PAM_LIBS) testdaemon: testdaemon.o $(CC) $(CFLAGS) -o testdaemon testdaemon.o diff --git a/config.h.in b/config.h.in index 013c38c..3be45e5 100644 --- a/config.h.in +++ b/config.h.in @@ -140,6 +140,12 @@ /* Define if you have the flock(3) function. */ #undef HAVE_FLOCK +/* Define to 1 if you have the `libpam,libpam_misc' library (-lpam,-lpam_misc). */ +#undef HAVE_PAM + +/* PAM support. */ +#undef WITH_PAM + /*****************************************************************************\ DON'T TOUCH ANYTHING BELOW HERE! \*****************************************************************************/ diff --git a/configure.in b/configure.in index 49becf3..e6fa10e 100644 --- a/configure.in +++ b/configure.in @@ -34,7 +34,6 @@ dnl Autoconf file for daemonize dnl dnl Process this file with autoconf to produce a configure script. dnl --------------------------------------------------------------------------- - AC_INIT(daemonize.c) AC_CONFIG_HEADER(config.h) @@ -53,6 +52,7 @@ AC_PROG_CPP AC_SUBST(CC) AC_SUBST(CPP) +AC_SUBST(DAEMONIZE_LIBS) dnl --------------------------------------------------------------------------- dnl UNIX variant hacks @@ -81,6 +81,24 @@ dnl --------------------------------------------------------------------------- dnl Checks for libraries. dnl --------------------------------------------------------------------------- +dnl check the existance of the libpam and libpam_misc +AC_ARG_WITH([pam], + AS_HELP_STRING([--with-pam], [enable PAM support]), + [], [with_pam=no]) +if test "x$with_pam" = xyes; then + LIBS_save=$LIBS + AC_CHECK_LIB(pam, pam_start, + [], + AC_MSG_ERROR([PAM selected but libpam not found])) + AC_CHECK_LIB(pam_misc, misc_conv, + [], + AC_MSG_ERROR([PAM selected but libpam_misc not found])) + LIBS=$LIBS_save + PAM_LIBS="-lpam -lpam_misc" + AC_DEFINE(WITH_PAM, [1] ,[PAM support.]) +fi +AC_SUBST([PAM_LIBS]) + dnl --------------------------------------------------------------------------- dnl Checks for typedefs, structures, and compiler characteristics. dnl --------------------------------------------------------------------------- From 819e8b9435469c5a5355efbfa21f79d142c21e09 Mon Sep 17 00:00:00 2001 From: Eric Keller Date: Fri, 15 Feb 2013 14:12:52 +0100 Subject: [PATCH 2/3] corresponding generated configure script generated by autoconf --- configure | 213 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 167 insertions(+), 46 deletions(-) diff --git a/configure b/configure index ab7c0d4..7567e2a 100755 --- a/configure +++ b/configure @@ -622,11 +622,13 @@ ac_includes_default="\ ac_subst_vars='LTLIBOBJS LIBOBJS LOCAL_MISSING_SOURCES +PAM_LIBS INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM EGREP GREP +DAEMONIZE_LIBS CPP OBJEXT EXEEXT @@ -676,6 +678,7 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking +with_pam ' ac_precious_vars='build_alias host_alias @@ -1289,6 +1292,11 @@ if test -n "$ac_init_help"; then cat <<\_ACEOF +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pam enable PAM support + Some influential environment variables: CC C compiler command CFLAGS C compiler flags @@ -1614,6 +1622,52 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_header_compile +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache @@ -1668,52 +1722,6 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_type -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - test -x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - as_fn_set_status $ac_retval - -} # ac_fn_c_try_link - # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly @@ -3072,6 +3080,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : @@ -3701,6 +3710,118 @@ export CPPFLAGS +# Check whether --with-pam was given. +if test "${with_pam+set}" = set; then : + withval=$with_pam; +else + with_pam=no +fi + +if test "x$with_pam" = xyes; then + LIBS_save=$LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5 +$as_echo_n "checking for pam_start in -lpam... " >&6; } +if ${ac_cv_lib_pam_pam_start+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pam_start (); +int +main () +{ +return pam_start (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pam_pam_start=yes +else + ac_cv_lib_pam_pam_start=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_start" >&5 +$as_echo "$ac_cv_lib_pam_pam_start" >&6; } +if test "x$ac_cv_lib_pam_pam_start" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPAM 1 +_ACEOF + + LIBS="-lpam $LIBS" + +else + as_fn_error $? "PAM selected but libpam not found" "$LINENO" 5 +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for misc_conv in -lpam_misc" >&5 +$as_echo_n "checking for misc_conv in -lpam_misc... " >&6; } +if ${ac_cv_lib_pam_misc_misc_conv+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam_misc $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char misc_conv (); +int +main () +{ +return misc_conv (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pam_misc_misc_conv=yes +else + ac_cv_lib_pam_misc_misc_conv=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_misc_misc_conv" >&5 +$as_echo "$ac_cv_lib_pam_misc_misc_conv" >&6; } +if test "x$ac_cv_lib_pam_misc_misc_conv" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPAM_MISC 1 +_ACEOF + + LIBS="-lpam_misc $LIBS" + +else + as_fn_error $? "PAM selected but libpam_misc not found" "$LINENO" 5 +fi + + LIBS=$LIBS_save + PAM_LIBS="-lpam -lpam_misc" + +$as_echo "#define WITH_PAM 1 " >>confdefs.h + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : From 597325c0a33ba4318181a009ff0081eb004ca9a8 Mon Sep 17 00:00:00 2001 From: Eric Keller Date: Fri, 15 Feb 2013 14:19:16 +0100 Subject: [PATCH 3/3] changes to support PAM session pam_access.so and pam_limits.so module when starting daemonize with another than root. Some examples of configuration: -- /etc/security/access.conf -- # deny access expect for localuser locally - : ALL EXCEPT localuser : LOCAL # User "localuser" should be allowed to get access via daemonize .. LOCAL. + : localuser : daemonize : LOCAL -- !/etc/security/access.conf -- -- /etc/pam.d/daemonize -- auth required pam_access.so session required pam_limits.so -- ! /etc/pam.d/daemonize -- -- /etc/security/limits.conf -- localuser - core unlimited localuser - rtprio unlimited localuser - nice unlimited localuser - memlock unlimited localuser hard nofile 2048 localuser soft nofile 2048 -- ! /etc/security/limits.conf -- Signed-off-by: Eric Keller --- daemonize.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/daemonize.c b/daemonize.c index 38ec0d0..96fb6ce 100644 --- a/daemonize.c +++ b/daemonize.c @@ -27,6 +27,21 @@ #include "config.h" #include "version.h" +#if WITH_PAM +/* use syslog */ +#include +/* PAM may include . */ +# undef setlocale +/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. + * Apparently they like to confuse people. */ +# include +# include +static const struct pam_conv conv = { + misc_conv, + NULL +}; +#endif /* WITH_PAM */ + /*---------------------------------------------------------------------------*\ Globals \*---------------------------------------------------------------------------*/ @@ -258,6 +273,14 @@ static void parse_params(int argc, char **argv) static void switch_user(const char *user_name, uid_t uid, const char *pid_file) { struct passwd *pw; +#if WITH_PAM + int pamret; + pam_handle_t *pamh; + const char *pamuser; + const char *failed_msg; + struct passwd pwdstruct; + char pwdbuf[256]; +#endif /* WITH_PAM */ if (uid != 0) die("Must be root to specify a different user.\n"); @@ -265,6 +288,39 @@ static void switch_user(const char *user_name, uid_t uid, const char *pid_file) if ( (pw = getpwnam(user_name)) == NULL ) die("Can't find user \"%s\" in password file.\n", user_name); +#if WITH_PAM + pamret = pam_start("daemonize", user, &conv, &pamh); + if (pamret != PAM_SUCCESS) { + syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "start", + pam_strerror(pamh, pamret), pamret); + } + + pamret = pam_authenticate(pamh, 0); + if (pamret != PAM_SUCCESS) { + syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "authenticate", + pam_strerror(pamh, pamret), pamret); + } + /* check that the account is healthy */ + pamret = pam_acct_mgmt(pamh, 0); + if (pamret != PAM_SUCCESS) { + syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "acct_mgmt", + pam_strerror(pamh, pamret), pamret); + } + + pamret = pam_open_session(pamh, 0); + if (pamret != PAM_SUCCESS) { + syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "open_session", + pam_strerror(pamh, pamret), pamret); + } + if (pamret == PAM_SUCCESS) + { + /* success */ + syslog(LOG_INFO, "pam_limits call success: %s (%d)", + pam_strerror(pamh, pamret), pamret); + } + +#endif /* WITH_PAM */ + if (setgid(pw->pw_gid) != 0) die("Can't set gid to %d: %s\n", pw->pw_gid, strerror (errno)); @@ -519,7 +575,6 @@ int main(int argc, char **argv) if (getenv("PATH") == NULL) setenv("PATH","/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin", 1); - execvp(cmd[0], cmd); die("Can't exec \"%s\": %s\n", cmd[0], strerror (errno));