int fd;
fd = open(bb_path_motd_file, O_RDONLY);
- if (fd) {
+ if (fd >= 0) {
fflush(stdout);
bb_copyfd_eof(fd, STDOUT_FILENO);
close(fd);
ndelay_on(1);
ndelay_on(2);
printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT);
+ /* unix API is brain damaged regarding O_NONBLOCK,
+ * we should undo it, or else we can affect other processes */
+ ndelay_off(1);
+ ndelay_off(2);
exit(EXIT_SUCCESS);
}
-int login_main(int argc, char **argv);
+int login_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int login_main(int argc, char **argv)
{
enum {
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;)
+#if ENABLE_PAM
+ int pamret;
+ pam_handle_t *pamh;
+ const char *pamuser;
+ const char *failed_msg;
+ struct passwd pwdstruct;
+ char pwdbuf[256];
+#endif
short_tty = full_tty;
username[0] = '\0';
* and any extra open fd's are closed.
* (The name of the function is misleading. Not daemonizing here.) */
bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
+ /* More of suid paranoia if called by non-root */
+ if (!amroot) {
+ /* Clear dangerous stuff, set PATH */
+ sanitize_env_for_suid();
+ }
opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
if (opt & LOGIN_OPT_f) {
openlog(applet_name, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH);
while (1) {
+
+ /* flush away any type-ahead (as getty does) */
+ (void) ioctl(0, TCFLSH, TCIFLUSH);
+
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";
+ failed_msg = "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)";
+ failed_msg = "set_item(TTY)";
goto pam_auth_failed;
}
pamret = pam_authenticate(pamh, 0);
if (pamret != PAM_SUCCESS) {
- failed_msg = "pam_authenticate";
+ failed_msg = "authenticate";
goto pam_auth_failed;
/* TODO: or just "goto auth_failed"
* since user seems to enter wrong password
/* check that the account is healthy */
pamret = pam_acct_mgmt(pamh, 0);
if (pamret != PAM_SUCCESS) {
- failed_msg = "account setup";
+ failed_msg = "acct_mgmt";
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));
+ pamuser = NULL;
+ /* 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 = "get_item(USER)";
+ goto pam_auth_failed;
}
- /* If we get here, the user was authenticated, and is
- * granted access. */
- pw = getpwnam(username);
- if (pw)
- break;
- goto auth_failed;
+ if (!pamuser || !pamuser[0])
+ goto auth_failed;
+ safe_strncpy(username, pamuser, sizeof(username));
+ /* Don't use "pw = getpwnam(username);",
+ * PAM is said to be capable of destroying static storage
+ * used by getpwnam(). We are using safe(r) function */
+ pw = NULL;
+ getpwnam_r(username, &pwdstruct, pwdbuf, sizeof(pwdbuf), &pw);
+ if (!pw)
+ goto auth_failed;
+ pamret = pam_open_session(pamh, 0);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "open_session";
+ goto pam_auth_failed;
+ }
+ pamret = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (pamret != PAM_SUCCESS) {
+ failed_msg = "setcred";
+ goto pam_auth_failed;
+ }
+ break; /* success, continue login process */
+
pam_auth_failed:
- bb_error_msg("%s failed: %s (%d)", failed_msg, pam_strerror(pamh, pamret), pamret);
+ bb_error_msg("pam_%s call failed: %s (%d)", failed_msg,
+ pam_strerror(pamh, pamret), pamret);
safe_strncpy(username, "UNKNOWN", sizeof(username));
#else /* not PAM */
pw = getpwnam(username);
fchown(0, pw->pw_uid, pw->pw_gid);
fchmod(0, 0600);
- if (ENABLE_LOGIN_SCRIPTS) {
+ /* We trust environment only if we run by root */
+ if (ENABLE_LOGIN_SCRIPTS && amroot) {
char *t_argv[2];
t_argv[0] = getenv("LOGIN_PRE_SUID_SCRIPT");