1
/* Copyright © 2005-2007 Roger Leigh <rleigh@debian.org>
3
* schroot is free software: you can redistribute it and/or modify it
4
* under the terms of the GNU General Public License as published by
5
* the Free Software Foundation, either version 3 of the License, or
6
* (at your option) any later version.
8
* schroot is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see
15
* <http://www.gnu.org/licenses/>.
17
*********************************************************************/
21
#include "sbuild-auth-pam-conv-tty.h"
22
#include "sbuild-ctty.h"
23
#include "sbuild-log.h"
31
#include <boost/format.hpp>
35
using namespace sbuild;
40
typedef std::pair<auth_pam_conv_tty::error_code,const char *> emap;
43
* This is a list of the supported error codes. It's used to
44
* construct the real error codes map.
48
emap(auth_pam_conv_tty::CTTY, N_("No controlling terminal")),
49
emap(auth_pam_conv_tty::TIMEOUT, N_("Timed out")),
50
// TRANSLATORS: Please use an ellipsis e.g. U+2026
51
emap(auth_pam_conv_tty::TIMEOUT_PENDING, N_("Time is running out...")),
52
emap(auth_pam_conv_tty::TERMIOS, N_("Failed to get terminal settings")),
53
// TRANSLATORS: %1% = integer
54
emap(auth_pam_conv_tty::CONV_TYPE, N_("Unsupported conversation type '%1%'"))
57
volatile sig_atomic_t timer_expired = false;
60
* Disable the alarm and signal handler.
62
* @param orig_sa the signal handler to restore.
65
reset_alarm (struct sigaction *orig_sa)
69
// Restore original handler
70
sigaction (SIGALRM, orig_sa, 0);
74
* Handle the SIGALRM signal.
76
* @param ignore the signal number (unused).
79
alarm_handler (int ignore)
85
* Set the SIGALARM handler, and set the timeout to delay seconds.
86
* The old signal handler is stored in orig_sa.
88
* @param delay the delay (in seconds) before SIGALRM is raised.
89
* @param orig_sa the location to store the original signal handler.
90
* @returns true on success, false on failure.
94
struct sigaction *orig_sa)
96
struct sigaction new_sa;
97
sigemptyset(&new_sa.sa_mask);
99
new_sa.sa_handler = alarm_handler;
101
if (sigaction(SIGALRM, &new_sa, orig_sa) != 0)
105
if (alarm(delay) != 0)
107
sigaction(SIGALRM, orig_sa, 0);
117
error<auth_pam_conv_tty::error_code>::map_type
118
error<auth_pam_conv_tty::error_code>::error_strings
120
init_errors + (sizeof(init_errors) / sizeof(init_errors[0])));
122
auth_pam_conv_tty::auth_pam_conv_tty (auth_ptr auth):
123
auth(weak_auth_ptr(auth)),
130
auth_pam_conv_tty::~auth_pam_conv_tty ()
135
auth_pam_conv_tty::create (auth_ptr auth)
137
return ptr(new auth_pam_conv_tty(auth));
140
auth_pam_conv::auth_ptr
141
auth_pam_conv_tty::get_auth ()
143
return auth_ptr(this->auth);
147
auth_pam_conv_tty::set_auth (auth_ptr auth)
149
this->auth = weak_auth_ptr(auth);
153
auth_pam_conv_tty::get_warning_timeout ()
155
return this->warning_timeout;
159
auth_pam_conv_tty::set_warning_timeout (time_t timeout)
161
this->warning_timeout = timeout;
165
auth_pam_conv_tty::get_fatal_timeout ()
167
return this->fatal_timeout;
171
auth_pam_conv_tty::set_fatal_timeout (time_t timeout)
173
this->fatal_timeout = timeout;
177
auth_pam_conv_tty::get_delay ()
180
time (&this->start_time);
182
if (this->fatal_timeout != 0 &&
183
this->start_time >= this->fatal_timeout)
184
throw error(TIMEOUT);
186
if (this->warning_timeout != 0 &&
187
this->start_time >= this->warning_timeout)
189
error e(TIMEOUT_PENDING);
190
log_ctty_exception_warning(e);
191
return (this->fatal_timeout ?
192
this->fatal_timeout - this->start_time : 0);
195
if (this->warning_timeout != 0)
196
return this->warning_timeout - this->start_time;
197
else if (this->fatal_timeout != 0)
198
return this->fatal_timeout - this->start_time;
204
auth_pam_conv_tty::read_string (std::string message,
210
struct termios orig_termios, noecho_termios;
211
struct sigaction saved_signals;
212
sigset_t old_sigs, new_sigs;
213
bool use_termios = false;
216
if (isatty(CTTY_FILENO))
220
if (tcgetattr(CTTY_FILENO, &orig_termios) != 0)
221
throw error(TERMIOS);
223
memcpy(&noecho_termios, &orig_termios, sizeof(struct termios));
226
noecho_termios.c_lflag &= ~(ECHO);
228
sigemptyset(&new_sigs);
229
sigaddset(&new_sigs, SIGINT);
230
sigaddset(&new_sigs, SIGTSTP);
231
sigprocmask(SIG_BLOCK, &new_sigs, &old_sigs);
234
char input[PAM_MAX_MSG_SIZE];
236
int delay = get_delay();
240
cctty << message << std::flush;
242
if (use_termios == true)
243
tcsetattr(CTTY_FILENO, TCSAFLUSH, &noecho_termios);
245
if (delay > 0 && set_alarm(delay, &saved_signals) == false)
249
int nchars = read(CTTY_FILENO, input, PAM_MAX_MSG_SIZE - 1);
252
tcsetattr(CTTY_FILENO, TCSADRAIN, &orig_termios);
253
if (echo == false && timer_expired == true)
257
reset_alarm(&saved_signals);
258
if (timer_expired == true)
267
if (input[nchars-1] == '\n')
268
input[--nchars] = '\0';
270
input[nchars] = '\0';
275
else if (nchars == 0)
286
memset(input, 0, sizeof(input));
288
if (use_termios == true)
290
sigprocmask(SIG_SETMASK, &old_sigs, 0);
291
tcsetattr(CTTY_FILENO, TCSADRAIN, &orig_termios);
298
auth_pam_conv_tty::conversation (auth_pam_conv::message_list& messages)
300
log_debug(DEBUG_NOTICE) << "PAM TTY conversation handler started" << endl;
302
for (std::vector<auth_pam_message>::iterator cur = messages.begin();
303
cur != messages.end();
308
case auth_pam_message::MESSAGE_PROMPT_NOECHO:
309
log_debug(DEBUG_NOTICE) << "PAM TTY input prompt (noecho)" << endl;
310
cur->response = read_string(cur->message, false);
312
case auth_pam_message::MESSAGE_PROMPT_ECHO:
313
log_debug(DEBUG_NOTICE) << "PAM TTY input prompt (echo)" << endl;
314
cur->response = read_string(cur->message, true);
316
case auth_pam_message::MESSAGE_ERROR:
317
log_debug(DEBUG_NOTICE) << "PAM TTY output error" << endl;
318
log_ctty_error() << cur->message << endl;
320
case auth_pam_message::MESSAGE_INFO:
321
log_debug(DEBUG_NOTICE) << "PAM TTY output info" << endl;
322
log_ctty_info() << cur->message << endl;
325
throw error(cur->type, CONV_TYPE);
330
log_debug(DEBUG_NOTICE) << "PAM TTY conversation handler ended" << endl;