summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIan Wienand <ianw@vmware.com>2011-09-14 08:41:38 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-09-14 08:41:38 +0200
commit378ab6819907fa9e439e93ed081c73c2351b4330 (patch)
tree2dff596f174929de10472a36a452462118613980
parenta221bc5f9909a6914ec6f4d14f76bb28c4a4cddf (diff)
login: new option LOGIN_SESSION_AS_CHILD
Signed-off-by: Ian Wienand <ianw@vmware.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--debianutils/run_parts.c3
-rw-r--r--loginutils/Config.src11
-rw-r--r--loginutils/login.c53
3 files changed, 61 insertions, 6 deletions
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 65cbfc338..8f08f6dc6 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -66,6 +66,7 @@ struct globals {
#define names (G.names)
#define cur (G.cur )
#define cmd (G.cmd )
+#define INIT_G() do { } while (0)
enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 };
@@ -143,6 +144,8 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv)
unsigned n;
int ret;
+ INIT_G();
+
#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS
applet_long_options = runparts_longopts;
#endif
diff --git a/loginutils/Config.src b/loginutils/Config.src
index 0d7f50cf1..14ce53434 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -205,6 +205,17 @@ config LOGIN
Note that Busybox binary must be setuid root for this applet to
work properly.
+config LOGIN_SESSION_AS_CHILD
+ bool "Run logged in session in a child process"
+ default y if PAM
+ depends on LOGIN
+ help
+ Run the logged in session in a child process. This allows
+ login to clean up things such as utmp entries or PAM sessions
+ when the login session is complete. If you use PAM, you
+ almost always would want this to be set to Y, else PAM session
+ will not be cleaned up.
+
config PAM
bool "Support for PAM (Pluggable Authentication Modules)"
default n
diff --git a/loginutils/login.c b/loginutils/login.c
index 2f7b9b212..534343129 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -41,8 +41,6 @@ enum {
TTYNAME_SIZE = 32,
};
-static char* short_tty;
-
#if ENABLE_FEATURE_NOLOGIN
static void die_if_nologin(void)
{
@@ -74,7 +72,7 @@ static void die_if_nologin(void)
#endif
#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
-static int check_securetty(void)
+static int check_securetty(const char *short_tty)
{
char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */
parser_t *parser = config_open2("/etc/securetty", fopen_for_read);
@@ -89,7 +87,7 @@ static int check_securetty(void)
return buf != NULL;
}
#else
-static ALWAYS_INLINE int check_securetty(void) { return 1; }
+static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; }
#endif
#if ENABLE_SELINUX
@@ -142,6 +140,29 @@ static void run_login_script(struct passwd *pw, char *full_tty)
void run_login_script(struct passwd *pw, char *full_tty);
#endif
+#if ENABLE_LOGIN_SESSION_AS_CHILD && ENABLE_PAM
+static void login_pam_end(pam_handle_t *pamh)
+{
+ int pamret;
+
+ pamret = pam_setcred(pamh, PAM_DELETE_CRED);
+ if (pamret != PAM_SUCCESS) {
+ bb_error_msg("pam_%s failed: %s (%d)", "setcred",
+ pam_strerror(pamh, pamret), pamret);
+ }
+ pamret = pam_close_session(pamh, 0);
+ if (pamret != PAM_SUCCESS) {
+ bb_error_msg("pam_%s failed: %s (%d)", "close_session",
+ pam_strerror(pamh, pamret), pamret);
+ }
+ pamret = pam_end(pamh, pamret);
+ if (pamret != PAM_SUCCESS) {
+ bb_error_msg("pam_%s failed: %s (%d)", "end",
+ pam_strerror(pamh, pamret), pamret);
+ }
+}
+#endif /* ENABLE_PAM */
+
static void get_username_or_die(char *buf, int size_buf)
{
int c, cntdown;
@@ -214,6 +235,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
char *opt_host = NULL;
char *opt_user = opt_user; /* for compiler */
char *full_tty;
+ char *short_tty;
IF_SELINUX(security_context_t user_sid = NULL;)
#if ENABLE_PAM
int pamret;
@@ -224,6 +246,9 @@ int login_main(int argc UNUSED_PARAM, char **argv)
char pwdbuf[256];
char **pamenv;
#endif
+#if ENABLE_LOGIN_SESSION_AS_CHILD
+ pid_t child_pid;
+#endif
username[0] = '\0';
signal(SIGALRM, alarm_handler);
@@ -359,7 +384,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
if (opt & LOGIN_OPT_f)
break; /* -f USER: success without asking passwd */
- if (pw->pw_uid == 0 && !check_securetty())
+ if (pw->pw_uid == 0 && !check_securetty(short_tty))
goto auth_failed;
/* Don't check the password if password entry is empty (!) */
@@ -393,7 +418,23 @@ int login_main(int argc UNUSED_PARAM, char **argv)
if (pw->pw_uid != 0)
die_if_nologin();
- IF_SELINUX(initselinux(username, full_tty, &user_sid));
+
+#if ENABLE_LOGIN_SESSION_AS_CHILD
+ child_pid = vfork();
+ if (child_pid != 0) {
+ if (child_pid < 0)
+ bb_perror_msg("vfork");
+ else {
+ if (safe_waitpid(child_pid, NULL, 0) == -1)
+ bb_perror_msg("waitpid");
+ update_utmp(child_pid, DEAD_PROCESS, NULL, NULL, NULL);
+ }
+ IF_PAM(login_pam_end(pamh);)
+ return 0;
+ }
+#endif
+
+ IF_SELINUX(initselinux(username, full_tty, &user_sid);)
/* Try these, but don't complain if they fail.
* _f_chown is safe wrt race t=ttyname(0);...;chown(t); */