* Test out PAM support, extend PAM support by providing environment

is specified by /etc/pam.d/init
 * Move utmp/wtmp before the execvp() in spawn() to be sure to
   use the correct pid even on a controlling tty
 * Remaining problem is that the pid of the second fork() for
   getting a controlling tty isn't that reported by spawn()
 * Re-enable writting utmp/wtmp for boot scripts
 * Provide a simply /etc/pam.d/init as without it will not work (sigh!)
This commit is contained in:
Werner Fink
2010-03-26 16:31:05 +00:00
parent 598cfa8acd
commit b2fec03199
4 changed files with 134 additions and 52 deletions

View File

@@ -67,6 +67,14 @@ sysvinit (2.88dsf) UNRELEASED; urgency=low
Bill Nottingham and Fedora. Bill Nottingham and Fedora.
* Add changes for Debian bug #68621 - Add PAM support for programs spawned * Add changes for Debian bug #68621 - Add PAM support for programs spawned
by init on the console like sulogin. Based on patch by Topi Miettinen. by init on the console like sulogin. Based on patch by Topi Miettinen.
* Test out PAM support, extend PAM support by providing environment
is specified by /etc/pam.d/init
* Move utmp/wtmp before the execvp() in spawn() to be sure to
use the correct pid even on a controlling tty
* Remaining problem is that the pid of the second fork() for
getting a controlling tty isn't that reported by spawn()
* Re-enable writting utmp/wtmp for boot scripts
* Provide a simply /etc/pam.d/init as without it will not work (sigh!)
-- Petter Reinholdtsen <pere@hungry.com> Sun, 12 Jul 2009 19:58:10 +0200 -- Petter Reinholdtsen <pere@hungry.com> Sun, 12 Jul 2009 19:58:10 +0200

View File

@@ -80,7 +80,9 @@ endif
# Additional libs for GNU libc. # Additional libs for GNU libc.
ifneq ($(findstring -DUSE_PAM,$(CPPFLAGS)),) ifneq ($(findstring -DUSE_PAM,$(CPPFLAGS)),)
INITLIBS += -lpam -lpam_misc INITLIBS += -lpam
PAMDOTD = /etc/pam.d
PAMINIT = $(PAMDOTD)/init
endif endif
# Additional libs for GNU libc. # Additional libs for GNU libc.
@@ -158,7 +160,13 @@ install:
$(STRIP) $$i ; \ $(STRIP) $$i ; \
$(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \ $(INSTALL_EXEC) $$i $(ROOT)/usr/bin/ ; \
done done
# $(INSTALL_EXEC) etc/initscript.sample $(ROOT)/etc/ ifneq ($(findstring -DUSE_PAM,$(CPPFLAGS)),)
$(INSTALL_DIR) $(ROOT)$(PAMDOTD)
test -s $(ROOT)$(PAMINIT) || \
$(INSTALL_DATA) init.sample $(ROOT)$(PAMINIT)
endif
# $(INSTALL_DIR) $(ROOT)/etc/
# $(INSTALL_EXEC) initscript.sample $(ROOT)/etc/
ln -sf halt $(ROOT)/sbin/reboot ln -sf halt $(ROOT)/sbin/reboot
ln -sf halt $(ROOT)/sbin/poweroff ln -sf halt $(ROOT)/sbin/poweroff
ln -sf init $(ROOT)/sbin/telinit ln -sf init $(ROOT)/sbin/telinit

View File

@@ -7,8 +7,8 @@
* *
* Version: @(#)init.c 2.86 30-Jul-2004 miquels@cistron.nl * Version: @(#)init.c 2.86 30-Jul-2004 miquels@cistron.nl
*/ */
#define VERSION "2.88" #define VERSION "2.89"
#define DATE "31-Jul-2004" #define DATE "26-Mar-2010"
/* /*
* This file is part of the sysvinit suite, * This file is part of the sysvinit suite,
* Copyright (C) 1991-2004 Miquel van Smoorenburg. * Copyright (C) 1991-2004 Miquel van Smoorenburg.
@@ -564,7 +564,7 @@ int console_open(int mode)
*/ */
for(f = 0; f < 5; f++) { for(f = 0; f < 5; f++) {
if ((fd = open(console_dev, m)) >= 0) break; if ((fd = open(console_dev, m)) >= 0) break;
usleep(100); usleep(10000);
} }
if (fd < 0) return fd; if (fd < 0) return fd;
@@ -865,6 +865,47 @@ void initlog(int loglevel, char *s, ...)
} }
#ifdef USE_PAM
static pam_handle_t *pamh = NULL;
# ifdef __GNUC__
static int
init_conv(int num_msg, const struct pam_message **msgm,
struct pam_response **response __attribute__((unused)),
void *appdata_ptr __attribute__((unused)))
# else
static int
init_conv(int num_msg, const struct pam_message **msgm,
struct pam_response **response, void *appdata_ptr)
# endif
{
int i;
for (i = 0; i < num_msg; i++) {
const struct pam_message *msg = msgm[i];
if (msg == (const struct pam_message*)0)
continue;
if (msg->msg == (char*)0)
continue;
switch (msg->msg_style) {
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
initlog(L_VB, "pam_message %s", msg->msg);
default:
break;
}
}
return 0;
}
static const struct pam_conv conv = { init_conv, NULL };
# define PAM_FAIL_CHECK(func, args...) \
{ \
if ((pam_ret = (func)(args)) != PAM_SUCCESS) { \
initlog(L_VB, "%s", pam_strerror(pamh, pam_ret)); \
goto pam_error; \
} \
}
#endif /* USE_PAM */
/* /*
* Build a new environment for execve(). * Build a new environment for execve().
*/ */
@@ -875,21 +916,38 @@ char **init_buildenv(int child)
char i_cons[32]; char i_cons[32];
char i_shell[] = "SHELL=" SHELL; char i_shell[] = "SHELL=" SHELL;
char **e; char **e;
#ifdef USE_PAM
char **pamenv = (char**)0;
#endif
int n, i; int n, i;
for (n = 0; environ[n]; n++) for (n = 0; environ[n]; n++)
; ;
n += NR_EXTRA_ENV + 8; n += NR_EXTRA_ENV;
if (child) {
#ifdef USE_PAM
pamenv = pam_getenvlist(pamh);
for (i = 0; pamenv[i]; i++)
;
n += i;
#endif
n += 8;
}
e = calloc(n, sizeof(char *)); e = calloc(n, sizeof(char *));
for (n = 0; environ[n]; n++) for (n = 0; environ[n]; n++)
e[n] = istrdup(environ[n]); e[n] = istrdup(environ[n]);
for (i = 0; i < NR_EXTRA_ENV; i++) for (i = 0; i < NR_EXTRA_ENV; i++) {
if (extra_env[i]) if (extra_env[i])
e[n++] = istrdup(extra_env[i]); e[n++] = istrdup(extra_env[i]);
}
if (child) { if (child) {
#ifdef USE_PAM
for (i = 0; pamenv[i]; i++)
e[n++] = istrdup(pamenv[i]);
#endif
snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev); snprintf(i_cons, sizeof(i_cons), "CONSOLE=%s", console_dev);
i_lvl[9] = thislevel; i_lvl[9] = thislevel;
i_prev[10] = prevlevel; i_prev[10] = prevlevel;
@@ -916,20 +974,6 @@ void init_freeenv(char **e)
} }
#ifdef USE_PAM
static pam_handle_t *pamh = NULL;
static const struct pam_conv conv = { misc_conv, NULL };
# define PAM_FAIL_CHECK(func, args...) \
{ \
const int __ret = (func)(args); \
if (__ret != PAM_SUCCESS) { \
initlog(L_VB, "%s", pam_strerror(pamh, __ret)); \
pam_end(pamh, __ret); \
exit(1); \
} \
}
#endif /* USE_PAM */
/* /*
* Fork and execute. * Fork and execute.
* *
@@ -937,11 +981,11 @@ static const struct pam_conv conv = { misc_conv, NULL };
* *
*/ */
static static
int spawn(CHILD *ch, int *res) pid_t spawn(CHILD *ch, int *res)
{ {
char *args[16]; /* Argv array */ char *args[16]; /* Argv array */
char buf[136]; /* Line buffer */ char buf[136]; /* Line buffer */
int f, st, rc; /* Scratch variables */ int f, st; /* Scratch variables */
char *ptr; /* Ditto */ char *ptr; /* Ditto */
time_t t; /* System time */ time_t t; /* System time */
int oldAlarm; /* Previous alarm value */ int oldAlarm; /* Previous alarm value */
@@ -1051,7 +1095,9 @@ int spawn(CHILD *ch, int *res)
sigprocmask(SIG_BLOCK, &nmask, &omask); sigprocmask(SIG_BLOCK, &nmask, &omask);
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
#ifdef USE_PAM
int pam_ret;
#endif
close(0); close(0);
close(1); close(1);
close(2); close(2);
@@ -1059,33 +1105,6 @@ int spawn(CHILD *ch, int *res)
sigprocmask(SIG_SETMASK, &omask, NULL); sigprocmask(SIG_SETMASK, &omask, NULL);
#ifdef USE_PAM
PAM_FAIL_CHECK(pam_start, "init", "root" , &conv, &pamh);
PAM_FAIL_CHECK(pam_set_item, pamh, PAM_TTY, console_dev);
PAM_FAIL_CHECK(pam_acct_mgmt, pamh, PAM_SILENT);
PAM_FAIL_CHECK(pam_open_session, pamh, PAM_SILENT);
PAM_FAIL_CHECK(pam_setcred, pamh, PAM_ESTABLISH_CRED|PAM_SILENT);
#endif
/*
* Update utmp/wtmp file prior to starting
* any child. This MUST be done right here in
* the child process in order to prevent a race
* condition that occurs when the child
* process' time slice executes before the
* parent (can and does happen in a uniprocessor
* environment). If the child is a getty and
* the race condition happens, then init's utmp
* update will happen AFTER the getty runs
* and expects utmp to be updated already!
*
* Do NOT log if process field starts with '+'
* FIXME: that's for compatibility with *very*
* old getties - probably it can be taken out.
*/
if (ch->action == RESPAWN && ch->process[0] != '+')
write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
/* /*
* In sysinit, boot, bootwait or single user mode: * In sysinit, boot, bootwait or single user mode:
* for any wait-type subprocess we _force_ the console * for any wait-type subprocess we _force_ the console
@@ -1119,6 +1138,7 @@ int spawn(CHILD *ch, int *res)
exit(1); exit(1);
} }
if (pid > 0) { if (pid > 0) {
pid_t rc;
/* /*
* Ignore keyboard signals etc. * Ignore keyboard signals etc.
* Then wait for child to exit. * Then wait for child to exit.
@@ -1173,6 +1193,32 @@ int spawn(CHILD *ch, int *res)
dup(f); dup(f);
} }
#ifdef USE_PAM
PAM_FAIL_CHECK(pam_start, "init", "root" , &conv, &pamh);
PAM_FAIL_CHECK(pam_set_item, pamh, PAM_TTY, console_dev);
PAM_FAIL_CHECK(pam_acct_mgmt, pamh, PAM_SILENT);
PAM_FAIL_CHECK(pam_open_session, pamh, PAM_SILENT);
PAM_FAIL_CHECK(pam_setcred, pamh, PAM_ESTABLISH_CRED|PAM_SILENT);
#endif
/*
* Update utmp/wtmp file prior to starting
* any child. This MUST be done right here in
* the child process in order to prevent a race
* condition that occurs when the child
* process' time slice executes before the
* parent (can and does happen in a uniprocessor
* environment). If the child is a getty and
* the race condition happens, then init's utmp
* update will happen AFTER the getty runs
* and expects utmp to be updated already!
*
* Do NOT log if process field starts with '+'
* FIXME: that's for compatibility with *very*
* old getties - probably it can be taken out.
*/
if (ch->process[0] != '+')
write_utmp_wtmp("", ch->id, getpid(), INIT_PROCESS, "");
/* Reset all the signals, set up environment */ /* Reset all the signals, set up environment */
for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART); for(f = 1; f < NSIG; f++) SETSIG(sa, f, SIG_DFL, SA_RESTART);
environ = init_buildenv(1); environ = init_buildenv(1);
@@ -1192,6 +1238,15 @@ int spawn(CHILD *ch, int *res)
execvp(args[1], args + 1); execvp(args[1], args + 1);
} }
initlog(L_VB, "cannot execute \"%s\"", args[1]); initlog(L_VB, "cannot execute \"%s\"", args[1]);
if (ch->process[0] != '+')
write_utmp_wtmp("", ch->id, getpid(), DEAD_PROCESS, NULL);
#ifdef USE_PAM
(void)pam_setcred(pamh, PAM_DELETE_CRED|PAM_SILENT);
pam_ret = pam_close_session(pamh, PAM_SILENT);
pam_error:
pam_end(pamh, pam_ret);
#endif
exit(1); exit(1);
} }
*res = pid; *res = pid;
@@ -2527,7 +2582,6 @@ void init_main(void)
CHILD *ch; CHILD *ch;
struct sigaction sa; struct sigaction sa;
sigset_t sgt; sigset_t sgt;
pid_t rc;
int f, st; int f, st;
if (!reload) { if (!reload) {
@@ -2613,6 +2667,7 @@ void init_main(void)
* See if we have to start an emergency shell. * See if we have to start an emergency shell.
*/ */
if (emerg_shell) { if (emerg_shell) {
pid_t rc;
SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART); SETSIG(sa, SIGCHLD, SIG_DFL, SA_RESTART);
if (spawn(&ch_emerg, &f) > 0) { if (spawn(&ch_emerg, &f) > 0) {
while((rc = wait(&st)) != f) while((rc = wait(&st)) != f)

11
src/init.sample Normal file
View File

@@ -0,0 +1,11 @@
#%PAM-1.0
#
# The PAM configuration file for /sbin/init
#
#
auth sufficient pam_rootok.so
auth include common-auth
account include common-account
password include common-password
session include common-session
session requisite pam_lastlog.so noupdate