Просмотр исходного кода

Add support for PAM sessions in start-stop-daemon.

Nicolas FRANCOIS лет назад: 19
Родитель
Сommit
d905c10fae
9 измененных файлов с 181 добавлено и 3 удалено
  1. 9 0
      ChangeLog
  2. 1 0
      configure.ac
  3. 4 0
      debian/changelog
  4. 2 1
      debian/control
  5. 31 0
      m4/libs.m4
  6. 4 0
      man/ChangeLog
  7. 3 0
      man/start-stop-daemon.8
  8. 1 1
      utils/Makefile.am
  9. 126 1
      utils/start-stop-daemon.c

+ 9 - 0
ChangeLog

@@ -1,3 +1,12 @@
+2007-03-25  Nicolas François  <nicolas.francois@centraliens.net>
+
+	* 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  <guillem@debian.org>
 
 	* debian/pseudo-tags: Renamed to ...

+ 1 - 0
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.

+ 4 - 0
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

+ 2 - 1
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

+ 31 - 0
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
+

+ 4 - 0
man/ChangeLog

@@ -1,3 +1,7 @@
+2007-03-25  Nicolas François  <nicolas.francois@centraliens.net>
+
+	* start-stop-daemon.8: Document the new --pam flag.
+
 2007-03-21  Guillem Jover  <guillem@debian.org>
 
 	* po/dpkg-man.pot: Regenerated.

+ 3 - 0
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

+ 1 - 1
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
 
 

+ 126 - 1
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 <sys/wait.h>
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+
+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 <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"
+#ifdef WITH_PAM
+"  -P|--pam <service>            open a session with this PAM service\n"
+#endif
 "  -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"
@@ -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 <service> */
+			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));
 }