{
debug_decl(sudo_term_noecho, SUDO_DEBUG_UTIL)
-again:
if (!changed && tcgetattr(fd, &oterm) != 0)
debug_return_bool(false);
(void) memcpy(&term, &oterm, sizeof(term));
changed = 1;
debug_return_bool(true);
}
- if (got_sigttou) {
- /* We were in the background, so oterm is probably bogus. */
- kill(getpid(), SIGTTOU);
- goto again;
- }
debug_return_bool(false);
}
struct termios term;
debug_decl(sudo_term_raw, SUDO_DEBUG_UTIL)
-again:
if (!changed && tcgetattr(fd, &oterm) != 0)
debug_return_bool(false);
(void) memcpy(&term, &oterm, sizeof(term));
changed = 1;
debug_return_bool(true);
}
- if (got_sigttou) {
- /* We were in the background, so oterm is probably bogus. */
- kill(getpid(), SIGTTOU);
- goto again;
- }
debug_return_bool(false);
}
{
debug_decl(sudo_term_cbreak, SUDO_DEBUG_UTIL)
-again:
if (!changed && tcgetattr(fd, &oterm) != 0)
debug_return_bool(false);
(void) memcpy(&term, &oterm, sizeof(term));
changed = 1;
debug_return_bool(true);
}
- if (got_sigttou) {
- /* We were in the background, so oterm is probably bogus. */
- kill(getpid(), SIGTTOU);
- goto again;
- }
debug_return_bool(false);
}
struct termios tt;
debug_decl(sudo_term_copy, SUDO_DEBUG_UTIL)
-again:
if (tcgetattr(src, &tt) != 0)
debug_return_bool(false);
if (tcsetattr_nobg(dst, TCSASOFT|TCSAFLUSH, &tt) == 0)
debug_return_bool(true);
- if (got_sigttou) {
- /* We were in the background, so tt is probably bogus. */
- kill(getpid(), SIGTTOU);
- goto again;
- }
debug_return_bool(false);
}
static bool display_lecture(int);
static struct passwd *get_authpw(int);
+struct getpass_closure {
+ void *cookie;
+ struct passwd *auth_pw;
+};
+
+/*
+ * Called when getpass is suspended so we can drop the lock.
+ */
+static int
+getpass_suspend(int signo, void *vclosure)
+{
+ struct getpass_closure *closure = vclosure;
+
+ timestamp_close(closure->cookie);
+ closure->cookie = NULL;
+ return 0;
+}
+
+/*
+ * Called when getpass is resumed so we can reacquire the lock.
+ */
+static int
+getpass_resume(int signo, void *vclosure)
+{
+ struct getpass_closure *closure = vclosure;
+
+ closure->cookie = timestamp_open(user_name, user_sid);
+ if (closure->cookie == NULL)
+ return -1;
+ if (!timestamp_lock(closure->cookie, closure->auth_pw))
+ return -1;
+ return 0;
+}
+
/*
* Returns true if the user successfully authenticates, false if not
* or -1 on fatal error.
static int
check_user_interactive(int validated, int mode, struct passwd *auth_pw)
{
+ struct sudo_conv_callback callback;
+ struct getpass_closure closure;
int status = TS_ERROR;
int rval = -1;
char *prompt;
- void *cookie;
bool lectured;
debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH)
SET(validated, FLAG_CHECK_USER);
/* Open timestamp file and check its status. */
- cookie = timestamp_open(user_name, user_sid);
- if (timestamp_lock(cookie, auth_pw))
- status = timestamp_status(cookie, auth_pw);
+ closure.auth_pw = auth_pw;
+ closure.cookie = timestamp_open(user_name, user_sid);
+ if (timestamp_lock(closure.cookie, auth_pw))
+ status = timestamp_status(closure.cookie, auth_pw);
switch (status) {
case TS_FATAL:
if (prompt == NULL)
goto done;
- rval = verify_user(auth_pw, prompt, validated, NULL); /* XXX */
+ /* Construct callback for getpass function. */
+ memset(&callback, 0, sizeof(callback));
+ callback.version = SUDO_CONV_CALLBACK_VERSION;
+ callback.closure = &closure;
+ callback.on_suspend = getpass_suspend;
+ callback.on_resume = getpass_resume;
+
+ rval = verify_user(auth_pw, prompt, validated, &callback);
if (rval == true && lectured)
(void)set_lectured(); /* lecture error not fatal */
free(prompt);
*/
if (rval == true && ISSET(validated, VALIDATE_SUCCESS) &&
!ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR) {
- (void)timestamp_update(cookie, auth_pw);
+ (void)timestamp_update(closure.cookie, auth_pw);
}
done:
- if (cookie != NULL)
- timestamp_close(cookie);
+ if (closure.cookie != NULL)
+ timestamp_close(closure.cookie);
debug_return_int(rval);
}
/* Set stdin to raw mode if it is a tty */
interactive = isatty(STDIN_FILENO);
if (interactive) {
- if (!sudo_term_raw(STDIN_FILENO, 1))
- sudo_fatal(U_("unable to set tty to raw mode"));
+ while (!sudo_term_raw(STDIN_FILENO, 1)) {
+ if (errno != EINTR)
+ sudo_fatal(U_("unable to set tty to raw mode"));
+ kill(getpid(), SIGTTOU);
+ }
}
/* Setup event base and input/output events. */
static char *getln(int, char *, size_t, int);
static char *sudo_askpass(const char *, const char *);
+static int
+suspend(int signo, struct sudo_conv_callback *callback)
+{
+ int rval = 0;
+ debug_decl(suspend, SUDO_DEBUG_CONV)
+
+ if (callback != NULL && callback->on_suspend != NULL) {
+ if (callback->on_suspend(signo, callback->closure) == -1)
+ rval = -1;
+ }
+ kill(getpid(), signo);
+ if (callback != NULL && callback->on_resume != NULL) {
+ if (callback->on_resume(signo, callback->closure) == -1)
+ rval = -1;
+ }
+ debug_return_int(rval);
+}
+
/*
* Like getpass(3) but with timeout and echo flags.
*/
/*
* If we are using a tty but are not the foreground pgrp this will
- * generate SIGTTOU, so do it *before* installing the signal handlers.
+ * return EINTR. We send ourself SIGTTOU bracketed by callbacks.
*/
if (!ISSET(flags, TGP_ECHO)) {
- if (ISSET(flags, TGP_MASK))
- neednl = sudo_term_cbreak(input);
- else
- neednl = sudo_term_noecho(input);
+ for (;;) {
+ if (ISSET(flags, TGP_MASK))
+ neednl = sudo_term_cbreak(input);
+ else
+ neednl = sudo_term_noecho(input);
+ if (neednl || errno != EINTR)
+ break;
+ /* Received SIGTTOU, suspend the process. */
+ if (suspend(SIGTTOU, callback) == -1) {
+ if (input != STDIN_FILENO)
+ (void) close(input);
+ debug_return_ptr(NULL);
+ }
+ }
}
/*
restore:
/* Restore old tty settings and signals. */
- if (!ISSET(flags, TGP_ECHO))
- sudo_term_restore(input, 1);
+ if (!ISSET(flags, TGP_ECHO)) {
+ for (;;) {
+ /* Restore old tty settings if possible. */
+ if (sudo_term_restore(input, 1) || errno != EINTR)
+ break;
+ /* Received SIGTTOU, suspend the process. */
+ if (suspend(SIGTTOU, callback) == -1) {
+ if (input != STDIN_FILENO)
+ (void) close(input);
+ debug_return_ptr(NULL);
+ }
+ }
+ }
(void) sigaction(SIGALRM, &savealrm, NULL);
(void) sigaction(SIGINT, &saveint, NULL);
(void) sigaction(SIGHUP, &savehup, NULL);
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
- if (callback != NULL && callback->on_suspend != NULL)
- callback->on_suspend(i, callback->closure);
+ if (suspend(i, callback) == 0)
+ need_restart = 1;
break;
- }
- kill(getpid(), i);
- switch (i) {
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- if (callback != NULL && callback->on_resume != NULL)
- callback->on_resume(i, callback->closure);
- need_restart = 1;
+ default:
+ kill(getpid(), i);
break;
}
}