From: Nicolas FRANCOIS Date: Sun, 25 Mar 2007 18:32:21 +0000 (+0000) Subject: Add support for PAM sessions in start-stop-daemon. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d905c10fae0ef623b59493a0e4a3d9081df2c2cc;p=dpkg Add support for PAM sessions in start-stop-daemon. --- diff --git a/ChangeLog b/ChangeLog index 3a0a4a57..92582eeb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-03-25 Nicolas François + + * utils/start-stop-daemon.c: Add support for PAM sessions. + * utils/Makefile.am: Link start-stop-daemon with the PAM libraries. + * m4/libs.m4: Add new test: DPKG_LIB_PAM. Defines WITH_PAM (by + default) and PAM_LIBS. Checks for the PAM library and header. + * configure.ac: Include PAM test. + * debian/control: New build dependency on libpam0g-dev. + 2007-03-23 Guillem Jover * debian/pseudo-tags: Renamed to ... diff --git a/configure.ac b/configure.ac index 8c787356..4992072e 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,7 @@ if test "x$build_dselect" = "xyes"; then fi if test "x$build_start_stop_daemon" = "xyes"; then DPKG_LIB_SSD + DPKG_LIB_PAM fi # Checks for header files. diff --git a/debian/changelog b/debian/changelog index d32044f9..e6222bbb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -59,6 +59,10 @@ dpkg (1.14.0) UNRELEASED; urgency=low Based on a patch by Jeffrey W. Baker. * Switch from pseudo-tags to usertags, and update the documentation. + [ Nicolas François ] + * Add support for PAM sessions in start-stop-daemon. + Closes: #376165, #406942 + [ Updated dpkg translations ] * Romanian (Eddy Petrișor). * Traditional Chinese (Anthony Wong). Closes: #415230 diff --git a/debian/control b/debian/control index 75517b47..b9aa08bf 100644 --- a/debian/control +++ b/debian/control @@ -8,7 +8,8 @@ Bugs: debbugs://bugs.debian.org Standards-Version: 3.7.2 Build-Depends: debhelper (>= 4.1.81), pkg-config, po4a (>= 0.23), libncurses5-dev | libncurses-dev, zlib1g-dev (>= 1:1.1.3-19.1), libbz2-dev, - libselinux1-dev (>= 1.28-4) [!hurd-i386 !kfreebsd-i386 !kfreebsd-amd64] + libselinux1-dev (>= 1.28-4) [!hurd-i386 !kfreebsd-i386 !kfreebsd-amd64], + libpam0g-dev Package: dpkg Architecture: any diff --git a/m4/libs.m4 b/m4/libs.m4 index f834026e..f6f4b0e9 100644 --- a/m4/libs.m4 +++ b/m4/libs.m4 @@ -108,3 +108,34 @@ AC_CHECK_LIB([ps], [proc_stat_list_create], [SSD_LIBS="${SSD_LIBS:+$SSD_LIBS }-l AC_CHECK_LIB([shouldbeinlibc], [fmt_past_time], [SSD_LIBS="${SSD_LIBS:+$SSD_LIBS }-lshouldbeinlibc"]) AC_CHECK_LIB([kvm], [kvm_openfiles], [SSD_LIBS="${SSD_LIBS:+$SSD_LIBS }-lkvm"]) ])# DPKG_LIB_SSD + +# DPKG_LIB_PAM +# ------------ +# Check for pam library. +AC_DEFUN([DPKG_LIB_PAM], +[AC_ARG_VAR([PAM_LIBS], [linker flags for pam library])dnl +AC_ARG_WITH(pam, + AS_HELP_STRING([--with-pam], + [use pam library for opening PAM sessions with start-stop-daemon])) +if test "x$with_pam" != "xno"; then + AC_CHECK_LIB([pam], [pam_start], + [AC_DEFINE(WITH_PAM, 1, + [Define to 1 to use PAM sessions in start-stop-daemon]) + if test "x$with_pam" = "xstatic"; then + dpkg_pam_libs="-Wl,-Bstatic -lpam -lpam_misc -Wl,-Bdynamic" + else + dpkg_pam_libs="-lpam -lpam_misc" + fi + PAM_LIBS="${PAM_LIBS:+$PAM_LIBS }$dpkg_pam_libs" + with_pam="yes"], + [if test -n "$with_pam"; then + AC_MSG_FAILURE([pam library not found]) + fi]) + + AC_CHECK_HEADER([security/pam_appl.h],, + [if test -n "$with_pam"; then + AC_MSG_FAILURE([pam header not found]) + fi]) +fi +])# DPKG_LIB_PAM + diff --git a/man/ChangeLog b/man/ChangeLog index 2b5d77a0..65dd4f4f 100644 --- a/man/ChangeLog +++ b/man/ChangeLog @@ -1,3 +1,7 @@ +2007-03-25 Nicolas François + + * start-stop-daemon.8: Document the new --pam flag. + 2007-03-21 Guillem Jover * po/dpkg-man.pot: Regenerated. diff --git a/man/start-stop-daemon.8 b/man/start-stop-daemon.8 index 6bc24960..0e299351 100644 --- a/man/start-stop-daemon.8 +++ b/man/start-stop-daemon.8 @@ -218,6 +218,9 @@ code for them to do this themself. .BR \-N ", " \-\-nicelevel " \fIint\fP" This alters the priority of the process before starting it. .TP +.BR \-P ", " \-\-pam " \fIpam_service\fP" +Start a PAM session, using the given PAM service. +.TP .BR \-k ", " \-\-umask " \fImask\fP" This sets the umask of the process before starting it. .TP diff --git a/utils/Makefile.am b/utils/Makefile.am index 9cfd988d..c7236d7d 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -13,7 +13,7 @@ if WITH_START_STOP_DAEMON start_stop_daemon_SOURCES = \ start-stop-daemon.c - start_stop_daemon_LDADD = ../getopt/libopt.a $(SSD_LIBS) + start_stop_daemon_LDADD = ../getopt/libopt.a $(SSD_LIBS) $(PAM_LIBS) endif diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c index 76c39a07..4652d515 100644 --- a/utils/start-stop-daemon.c +++ b/utils/start-stop-daemon.c @@ -140,6 +140,20 @@ static const char *progname = ""; static int nicelevel = 0; static int umask_value = -1; +#ifdef WITH_PAM +#include +#include +#include + +static pam_handle_t *pamh = NULL; +static char *pam = NULL; + +static struct pam_conv conv = { + misc_conv, + NULL +}; +#endif + static struct stat exec_stat; #if defined(OSHURD) static struct proc_stat_list *procset = NULL; @@ -224,6 +238,13 @@ fatal(const char *format, ...) { va_list arglist; +#ifdef WITH_PAM + if (pamh) { + int retcode = pam_close_session(pamh,0); + pam_end(pamh,retcode); + } +#endif + fprintf(stderr, "%s: ", progname); va_start(arglist, format); vfprintf(stderr, format, arglist); @@ -306,6 +327,9 @@ do_help(void) " -r|--chroot chroot to before starting\n" " -d|--chdir change to (default is /)\n" " -N|--nicelevel add incr to the process's nice level\n" +#ifdef WITH_PAM +" -P|--pam open a session with this PAM service\n" +#endif " -k|--umask change the umask to before starting\n" " -b|--background force the process to detach\n" " -m|--make-pidfile create the pidfile before starting\n" @@ -510,8 +534,11 @@ parse_options(int argc, char * const *argv) { "umask", 1, NULL, 'k'}, { "background", 0, NULL, 'b'}, { "make-pidfile", 0, NULL, 'm'}, - { "retry", 1, NULL, 'R'}, + { "retry", 1, NULL, 'R'}, { "chdir", 1, NULL, 'd'}, +#ifdef WITH_PAM + { "pam", 1, NULL, 'P'}, +#endif { NULL, 0, NULL, 0} }; const char *umask_str = NULL; @@ -598,6 +625,11 @@ parse_options(int argc, char * const *argv) case 'd': /* --chdir /new/dir */ changedir = optarg; break; +#ifdef WITH_PAM + case 'P': /* --pam */ + pam = optarg; + break; +#endif default: badusage(NULL); /* message printed by getopt */ } @@ -1326,6 +1358,68 @@ main(int argc, char **argv) #endif devnull_fd=open("/dev/null", O_RDWR); } +#ifdef WITH_PAM + /* + * If PAM is enabled, start the PAM library, and open a PAM + * session. + * Set the environment variable set by the PAM modules for the + * daemon. + */ + if (pam) { + int retcode; + char **envcp; + + char *pam_user; + struct passwd *pw; + pw = getpwuid((-1==runas_uid)?getuid():runas_uid); + if (!pw) { + fatal("user ID `%d' not found\n", + (-1==runas_uid)?getuid():runas_uid); + } + else { + pam_user = strdup(pw->pw_name); + if (!pam_user) + fatal("Unable to allocate memory: %s", strerror(errno)); + } + + retcode = pam_start (pam, pam_user, &conv, &pamh); + if (PAM_SUCCESS != retcode) { + fprintf(stderr, "%s\n", pam_strerror(pamh, retcode)); + pam_end(pamh, retcode); + exit(2); + } + + /* Some PAM modules may rely on PAM_RUSER */ + if (pam_user) { + int retcode = pam_set_item(pamh, PAM_RUSER, pam_user); + if (PAM_SUCCESS != retcode) { + fprintf(stderr, + "%s\n", + pam_strerror(pamh, retcode)); + pam_end(pamh, retcode); + exit(2); + } + } + + retcode = pam_open_session(pamh, 0); + if (PAM_SUCCESS != retcode) { + fprintf(stderr, "%s\n", pam_strerror(pamh, retcode)); + pam_end(pamh, retcode); + exit(2); + } + + /* Copy the environment variables set by the PAM modules. */ + envcp = pam_getenvlist (pamh); + if (envcp) { + while (*envcp) { + int err = putenv(*envcp); + if (err) + fatal("Unable to set the '%s' environment variable: %s", *envcp, strerror(errno)); + envcp++; + } + } + } +#endif if (nicelevel) { errno=0; if ((nice(nicelevel)==-1) && (errno!=0)) @@ -1386,6 +1480,37 @@ main(int argc, char **argv) setpgid(0,0); #endif } +#ifdef WITH_PAM + /* + * If PAM is enabled, fork. + * The parent keeps the PAM session (and will do the cleanup). + * The child will start the daemon. + */ + if (pam) { + int parent = fork(); + if (parent < 0) { + fatal("Unable to fork.\n"); + } + if (parent) { + /* parent: wait for child to finish, + * then cleanup the PAM session. + */ + int retcode; + int status = 1; + wait(&status); + + retcode = pam_close_session(pamh,0); + pam_end(pamh,retcode); + + if (WIFSIGNALED(status)) + status = 1; + else + status = WEXITSTATUS(status); + exit(status); + } + /* Only child continue */ + } +#endif execv(startas, argv); fatal("Unable to start %s: %s", startas, strerror(errno)); }