summaryrefslogtreecommitdiffstats
path: root/login-utils/login.c
diff options
context:
space:
mode:
Diffstat (limited to 'login-utils/login.c')
-rw-r--r--login-utils/login.c108
1 files changed, 71 insertions, 37 deletions
diff --git a/login-utils/login.c b/login-utils/login.c
index 1812b90..c8544f6 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -46,6 +46,7 @@
#include <grp.h>
#include <pwd.h>
#include <utmpx.h>
+#include <path.h>
#ifdef HAVE_LASTLOG_H
# include <lastlog.h>
@@ -172,9 +173,10 @@ static void __attribute__((__noreturn__))
struct termios ti;
/* reset echo */
- tcgetattr(0, &ti);
- ti.c_lflag |= ECHO;
- tcsetattr(0, TCSANOW, &ti);
+ if (tcgetattr(0, &ti) >= 0) {
+ ti.c_lflag |= ECHO;
+ tcsetattr(0, TCSANOW, &ti);
+ }
_exit(EXIT_SUCCESS); /* %% */
}
@@ -508,12 +510,14 @@ static void chown_tty(struct login_context *cxt)
static void init_tty(struct login_context *cxt)
{
struct stat st;
- struct termios tt, ttt;
- struct winsize ws;
+ struct termios tt, ttt = { 0 };
+ struct winsize ws = { 0 };
+ int fd;
cxt->tty_mode = (mode_t) getlogindefs_num("TTYPERM", TTY_MODE);
get_terminal_name(&cxt->tty_path, &cxt->tty_name, &cxt->tty_number);
+ fd = get_terminal_stdfd();
/*
* In case login is suid it was possible to use a hardlink as stdin
@@ -526,7 +530,7 @@ static void init_tty(struct login_context *cxt)
if (!cxt->tty_path || !*cxt->tty_path ||
lstat(cxt->tty_path, &st) != 0 || !S_ISCHR(st.st_mode) ||
(st.st_nlink > 1 && strncmp(cxt->tty_path, "/dev/", 5) != 0) ||
- access(cxt->tty_path, R_OK | W_OK) != 0) {
+ access(cxt->tty_path, R_OK | W_OK) != 0 || fd == -EINVAL) {
syslog(LOG_ERR, _("FATAL: bad tty"));
sleepexit(EXIT_FAILURE);
@@ -542,15 +546,20 @@ static void init_tty(struct login_context *cxt)
/* The TTY size might be reset to 0x0 by the kernel when we close the stdin/stdout/stderr file
* descriptors so let's save the size now so we can reapply it later */
- memset(&ws, 0, sizeof(struct winsize));
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
+ if (ioctl(fd, TIOCGWINSZ, &ws) < 0) {
syslog(LOG_WARNING, _("TIOCGWINSZ ioctl failed: %m"));
+ ws.ws_row = 0;
+ ws.ws_col = 0;
+ }
- tcgetattr(0, &tt);
- ttt = tt;
- ttt.c_cflag &= ~HUPCL;
+ if (tcgetattr(fd, &tt) >= 0) {
+ ttt = tt;
+ ttt.c_cflag &= ~HUPCL;
+ } else {
+ ttt.c_cflag = HUPCL;
+ }
- if ((fchown(0, 0, 0) || fchmod(0, cxt->tty_mode)) && errno != EROFS) {
+ if ((fchown(fd, 0, 0) || fchmod(fd, cxt->tty_mode)) && errno != EROFS) {
syslog(LOG_ERR, _("FATAL: %s: change permissions failed: %m"),
cxt->tty_path);
@@ -558,7 +567,8 @@ static void init_tty(struct login_context *cxt)
}
/* Kill processes left on this tty */
- tcsetattr(0, TCSANOW, &ttt);
+ if ((ttt.c_cflag & HUPCL) == 0)
+ tcsetattr(fd, TCSANOW, &ttt);
/*
* Let's close file descriptors before vhangup
@@ -576,7 +586,8 @@ static void init_tty(struct login_context *cxt)
open_tty(cxt->tty_path);
/* restore tty modes */
- tcsetattr(0, TCSAFLUSH, &tt);
+ if ((ttt.c_cflag & HUPCL) == 0)
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
/* Restore tty size */
if ((ws.ws_row > 0 || ws.ws_col > 0)
@@ -634,16 +645,16 @@ static void log_audit(struct login_context *cxt, int status)
if (!pwd && cxt->username)
pwd = getpwnam(cxt->username);
- audit_log_acct_message(audit_fd,
- AUDIT_USER_LOGIN,
- NULL,
- "login",
- cxt->username ? cxt->username : "(unknown)",
- pwd ? pwd->pw_uid : (unsigned int)-1,
- cxt->hostname,
- NULL,
- cxt->tty_name,
- status);
+ ignore_result( audit_log_acct_message(audit_fd,
+ AUDIT_USER_LOGIN,
+ NULL,
+ "login",
+ cxt->username ? cxt->username : "(unknown)",
+ pwd ? pwd->pw_uid : (unsigned int)-1,
+ cxt->hostname,
+ NULL,
+ cxt->tty_name,
+ status) );
close(audit_fd);
}
@@ -850,8 +861,7 @@ static void loginpam_err(pam_handle_t *pamh, int retcode)
static const char *loginpam_get_prompt(struct login_context *cxt)
{
const char *host;
- char *prompt, *dflt_prompt = _("login: ");
- size_t sz;
+ char *prompt = NULL, *dflt_prompt = _("login: ");
if (cxt->nohost)
return dflt_prompt; /* -H on command line */
@@ -862,9 +872,7 @@ static const char *loginpam_get_prompt(struct login_context *cxt)
if (!(host = get_thishost(cxt, NULL)))
return dflt_prompt;
- sz = strlen(host) + 1 + strlen(dflt_prompt) + 1;
- prompt = xmalloc(sz);
- snprintf(prompt, sz, "%s %s", host, dflt_prompt);
+ xasprintf(&prompt, "%s %s", host, dflt_prompt);
return prompt;
}
@@ -1283,6 +1291,28 @@ static void __attribute__((__noreturn__)) usage(void)
exit(EXIT_SUCCESS);
}
+static void load_credentials(struct login_context *cxt) {
+ char str[32] = { 0 };
+ char *env;
+ struct path_cxt *pc;
+
+ env = safe_getenv("CREDENTIALS_DIRECTORY");
+ if (!env)
+ return;
+
+ pc = ul_new_path("%s", env);
+ if (!pc) {
+ syslog(LOG_WARNING, _("failed to initialize path context"));
+ return;
+ }
+
+ if (ul_path_read_buffer(pc, str, sizeof(str), "login.noauth") > 0
+ && *str && strcmp(str, "yes") == 0)
+ cxt->noauth = 1;
+
+ ul_unref_path(pc);
+}
+
static void initialize(int argc, char **argv, struct login_context *cxt)
{
int c;
@@ -1318,6 +1348,8 @@ static void initialize(int argc, char **argv, struct login_context *cxt)
setpriority(PRIO_PROCESS, 0, 0);
process_title_init(argc, argv);
+ load_credentials(cxt);
+
while ((c = getopt_long(argc, argv, "fHh:pV", longopts, NULL)) != -1)
switch (c) {
case 'f':
@@ -1388,6 +1420,7 @@ int main(int argc, char **argv)
.conv = { openpam_ttyconv, NULL } /* OpenPAM conversation function */
#endif
};
+ bool script;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1512,7 +1545,9 @@ int main(int argc, char **argv)
}
/* if the shell field has a space: treat it like a shell script */
- if (strchr(pwd->pw_shell, ' ')) {
+ script = strchr(pwd->pw_shell, ' ') != NULL;
+
+ if (script) {
char *buff;
xasprintf(&buff, "exec %s", pwd->pw_shell);
@@ -1521,14 +1556,13 @@ int main(int argc, char **argv)
child_argv[child_argc++] = "-c";
child_argv[child_argc++] = buff;
} else {
- char tbuf[PATH_MAX + 2], *p;
-
- tbuf[0] = '-';
- xstrncpy(tbuf + 1, ((p = strrchr(pwd->pw_shell, '/')) ?
- p + 1 : pwd->pw_shell), sizeof(tbuf) - 1);
+ char *buff, *p;
+ xasprintf(&buff, "-%.*s", PATH_MAX,
+ ((p = strrchr(pwd->pw_shell, '/')) ?
+ p + 1 : pwd->pw_shell));
child_argv[child_argc++] = pwd->pw_shell;
- child_argv[child_argc++] = xstrdup(tbuf);
+ child_argv[child_argc++] = buff;
}
child_argv[child_argc++] = NULL;
@@ -1538,7 +1572,7 @@ int main(int argc, char **argv)
execvp(child_argv[0], child_argv + 1);
- if (!strcmp(child_argv[0], "/bin/sh"))
+ if (script)
warn(_("couldn't exec shell script"));
else
warn(_("no shell"));