#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,
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;
LOGIN_OPT_h = (1<<1),
LOGIN_OPT_p = (1<<2),
};
- char fromhost[512];
+ char *fromhost;
char username[USERNAME_SIZE];
const char *tmp;
int amroot;
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';
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);
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");
/* 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",
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();
* 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 */
}