block 373786 by 406942
merge 376165 406942
tags 376165 patch
thanks
Hi,
In both #376165 and #406942, you asked for PAM support in
start-stop-daemon.
The attached patch adds a --pam <service> option to start-stop-daemon.
It only implements PAM session (i.e. no authentication, etc), which I
guess is sufficient.
Marc, does it work with the exim use case? (It would mean adding something
like --pam exim-cron, and interested users should create
/etc/pam.d/exim-cron).
I tested it with the pam_tmpdir module and tested the --chuid and
--background options.
(s-s-d --pam test -S --chuid test -x /tmp/sh -- -c "echo \$TMPDIR")
Russel, it would be nice if you could test the patch with the
pam_namespace module.
Kind Regards,
--
Nekral
Index: utils/start-stop-daemon.c
===================================================================
--- utils/start-stop-daemon.c (révision 650)
+++ utils/start-stop-daemon.c (copie de travail)
@@ -88,6 +88,9 @@
#include <limits.h>
#include <assert.h>
#include <ctype.h>
+#include <sys/wait.h>
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
#ifdef HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
@@ -140,6 +143,14 @@
static int nicelevel = 0;
static int umask_value = -1;
+static pam_handle_t *pamh = NULL;
+static char *pam = NULL;
+
+static struct pam_conv conv = {
+ misc_conv,
+ NULL
+};
+
static struct stat exec_stat;
#if defined(OSHURD)
static struct proc_stat_list *procset = NULL;
@@ -224,6 +235,10 @@
{
va_list arglist;
+ if (pamh) {
+ int retcode = pam_close_session(pamh,0);
+ pam_end(pamh,retcode);
+ }
fprintf(stderr, "%s: ", progname);
va_start(arglist, format);
vfprintf(stderr, format, arglist);
@@ -306,6 +321,7 @@
" -r|--chroot <directory> chroot to <directory> before starting\n"
" -d|--chdir <directory> change to <directory> (default is /)\n"
" -N|--nicelevel <incr> add incr to the process's nice level\n"
+" -P|--pam <service> open a session with this PAM service\n"
" -k|--umask <mask> change the umask to <mask> before starting\n"
" -b|--background force the process to detach\n"
" -m|--make-pidfile create the pidfile before starting\n"
@@ -512,6 +528,7 @@
{ "make-pidfile", 0, NULL, 'm'},
{ "retry", 1, NULL, 'R'},
{ "chdir", 1, NULL, 'd'},
+ { "pam", 1, NULL, 'P'},
{ NULL, 0, NULL, 0}
};
const char *umask_str = NULL;
@@ -598,6 +615,9 @@
case 'd': /* --chdir /new/dir */
changedir = optarg;
break;
+ case 'P': /* --pam <service> */
+ pam = optarg;
+ break;
default:
badusage(NULL); /* message printed by getopt */
}
@@ -1326,6 +1346,62 @@
#endif
devnull_fd=open("/dev/null", O_RDWR);
}
+ 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);
+ }
+ }
+ /* FIXME: set some other PAM variables?
+ */
+
+ 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++;
+ }
+ }
+ }
if (nicelevel) {
errno=0;
if ((nice(nicelevel)==-1) && (errno!=0))
@@ -1386,6 +1462,30 @@
setpgid(0,0);
#endif
}
+ if (NULL != 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;
+ (void) 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 */
+ }
execv(startas, argv);
fatal("Unable to start %s: %s", startas, strerror(errno));
}
Index: utils/Makefile.am
===================================================================
--- utils/Makefile.am (révision 650)
+++ utils/Makefile.am (copie de travail)
@@ -13,7 +13,7 @@
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) -lpam -lpam_misc
endif
Index: man/start-stop-daemon.8
===================================================================
--- man/start-stop-daemon.8 (révision 650)
+++ man/start-stop-daemon.8 (copie de travail)
@@ -227,6 +227,9 @@
\fB\-N\fP|\fB\-\-nicelevel\fP \fIint\fP
This alters the priority of the process before starting it.
.TP
+\fB\-P\fP|\fB\-\-pam\fP \fIpam_service\fP
+Start a PAM session, using the given PAM service.
+.TP
\fB\-k\fP|\fB\-\-umask\fP \fImask\fP
This sets the umask of the process before starting it.
.TP