setup_environment: code shrink
[oweals/busybox.git] / loginutils / login.c
index 7b60fd017caa6fdab1ead31deae522d60efbc32e..7f89075439e72de7a3fb73876999595dba063d3d 100644 (file)
 #include <selinux/flask.h> /* for security class definitions  */
 #endif
 
+#if ENABLE_PAM
+/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
+#undef setlocale
+/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx.
+ * Apparently they like to confuse people. */
+#include <security/pam_appl.h>
+#include <security/pam_misc.h>
+static const struct pam_conv conv = {
+       misc_conv,
+       NULL
+};
+#endif
+
 enum {
        TIMEOUT = 60,
        EMPTY_USERNAME_COUNT = 10,
@@ -125,7 +138,7 @@ static void die_if_nologin_and_non_root(int amroot)
 static ALWAYS_INLINE void die_if_nologin_and_non_root(int amroot) {}
 #endif
 
-#if ENABLE_FEATURE_SECURETTY
+#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM
 static int check_securetty(void)
 {
        FILE *fp;
@@ -214,7 +227,7 @@ int login_main(int argc, char **argv)
                LOGIN_OPT_h = (1<<1),
                LOGIN_OPT_p = (1<<2),
        };
-       char fromhost[512];
+       char *fromhost;
        char username[USERNAME_SIZE];
        const char *tmp;
        int amroot;
@@ -226,6 +239,9 @@ int login_main(int argc, char **argv)
        char full_tty[TTYNAME_SIZE];
        USE_SELINUX(security_context_t user_sid = NULL;)
        USE_FEATURE_UTMP(struct utmp utent;)
+       USE_PAM(pam_handle_t *pamh;)
+       USE_PAM(int pamret;)
+       USE_PAM(const char *failed_msg;)
 
        short_tty = full_tty;
        username[0] = '\0';
@@ -265,13 +281,12 @@ int login_main(int argc, char **argv)
                USE_FEATURE_UTMP(
                        safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));
                )
-               snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s' from "
-                                       "'%.200s'", short_tty, opt_host);
+               fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
        } else
-               snprintf(fromhost, sizeof(fromhost)-1, " on '%.100s'", short_tty);
+               fromhost = xasprintf(" on '%s'", short_tty);
 
-       // Was breaking "login <username>" from shell command line:
-       // bb_setpgrp();
+       /* Was breaking "login <username>" from shell command line: */
+       /*bb_setpgrp();*/
 
        openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
 
@@ -279,6 +294,54 @@ int login_main(int argc, char **argv)
                if (!username[0])
                        get_username_or_die(username, sizeof(username));
 
+#if ENABLE_PAM
+               pamret = pam_start("login", username, &conv, &pamh);
+               if (pamret != PAM_SUCCESS) {
+                       failed_msg = "pam_start";
+                       goto pam_auth_failed;
+               }
+               /* set TTY (so things like securetty work) */
+               pamret = pam_set_item(pamh, PAM_TTY, short_tty);
+               if (pamret != PAM_SUCCESS) {
+                       failed_msg = "pam_set_item(TTY)";
+                       goto pam_auth_failed;
+               }
+               pamret = pam_authenticate(pamh, 0);
+               if (pamret != PAM_SUCCESS) {
+                       failed_msg = "pam_authenticate";
+                       goto pam_auth_failed;
+                       /* TODO: or just "goto auth_failed"
+                        * since user seems to enter wrong password
+                        * (in this case pamret == 7)
+                        */
+               }
+               /* check that the account is healthy */
+               pamret = pam_acct_mgmt(pamh, 0);
+               if (pamret != PAM_SUCCESS) {
+                       failed_msg = "account setup";
+                       goto pam_auth_failed;
+               }
+               /* read user back */
+               {
+                       const char *pamuser;
+                       /* gcc: "dereferencing type-punned pointer breaks aliasing rules..."
+                        * thus we cast to (void*) */
+                       if (pam_get_item(pamh, PAM_USER, (void*)&pamuser) != PAM_SUCCESS) {
+                               failed_msg = "pam_get_item(USER)";
+                               goto pam_auth_failed;
+                       }
+                       safe_strncpy(username, pamuser, sizeof(username));
+               }
+               /* If we get here, the user was authenticated, and is
+                * granted access. */
+               pw = getpwnam(username);
+               if (pw)
+                       break;
+               goto auth_failed;
+ pam_auth_failed:
+               bb_error_msg("%s failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret);
+               safe_strncpy(username, "UNKNOWN", sizeof(username));
+#else /* not PAM */
                pw = getpwnam(username);
                if (!pw) {
                        strcpy(username, "UNKNOWN");
@@ -301,9 +364,11 @@ int login_main(int argc, char **argv)
                /* authorization takes place here */
                if (correct_password(pw))
                        break;
+#endif /* ENABLE_PAM */
  auth_failed:
                opt &= ~LOGIN_OPT_f;
                bb_do_delay(FAIL_DELAY);
+               /* TODO: doesn't sound like correct English phrase to me */
                puts("Login incorrect");
                if (++count == 3) {
                        syslog(LOG_WARNING, "invalid password for '%s'%s",
@@ -367,7 +432,9 @@ int login_main(int argc, char **argv)
        tmp = pw->pw_shell;
        if (!tmp || !*tmp)
                tmp = DEFAULT_SHELL;
+       /* setup_environment params: shell, loginshell, changeenv, pw */
        setup_environment(tmp, 1, !(opt & LOGIN_OPT_p), pw);
+       /* FIXME: login shell = 1 -> 3rd parameter is ignored! */
 
        motd();
 
@@ -398,7 +465,8 @@ int login_main(int argc, char **argv)
         * should it leave SIGINT etc enabled or disabled? */
        signal(SIGINT, SIG_DFL);
 
-       run_shell(tmp, 1, 0, 0);        /* exec the shell finally */
+       /* Exec login shell with no additional parameters */
+       run_shell(tmp, 1, NULL, NULL);
 
-       return EXIT_FAILURE;
+       /* return EXIT_FAILURE; - not reached */
 }