diff options
Diffstat (limited to 'login-utils/login.c')
-rw-r--r-- | login-utils/login.c | 108 |
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")); |