openpam_ttyconv.c revision 105770
1/*- 2 * Copyright (c) 2002 Networks Associates Technology, Inc. 3 * All rights reserved. 4 * 5 * This software was developed for the FreeBSD Project by ThinkSec AS and 6 * Network Associates Laboratories, the Security Research Division of 7 * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 8 * ("CBOSS"), as part of the DARPA CHATS research program. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote 19 * products derived from this software without specific prior written 20 * permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $P4: //depot/projects/openpam/lib/openpam_ttyconv.c#13 $ 35 */ 36 37#include <sys/types.h> 38 39#include <ctype.h> 40#include <setjmp.h> 41#include <signal.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <termios.h> 46#include <unistd.h> 47 48#include <security/pam_appl.h> 49#include <security/openpam.h> 50 51int openpam_ttyconv_timeout = 0; 52static jmp_buf jmpenv; 53static int timed_out; 54 55static void 56timeout(int sig) 57{ 58 timed_out = 1; 59 longjmp(jmpenv, sig); 60} 61 62static char * 63prompt(const char *msg) 64{ 65 char buf[PAM_MAX_RESP_SIZE]; 66 struct sigaction action, saved_action; 67 sigset_t saved_sigset, sigset; 68 unsigned int saved_alarm; 69 size_t len; 70 71 sigemptyset(&sigset); 72 sigaddset(&sigset, SIGINT); 73 sigaddset(&sigset, SIGTSTP); 74 sigprocmask(SIG_SETMASK, &sigset, &saved_sigset); 75 action.sa_handler = &timeout; 76 action.sa_flags = 0; 77 sigemptyset(&action.sa_mask); 78 sigaction(SIGALRM, &action, &saved_action); 79 fputs(msg, stdout); 80 buf[0] = '\0'; 81 timed_out = 0; 82 saved_alarm = alarm(openpam_ttyconv_timeout); 83 if (setjmp(jmpenv) == 0) 84 fgets(buf, sizeof buf, stdin); 85 else 86 fputs(" timeout!\n", stderr); 87 alarm(0); 88 sigaction(SIGALRM, &saved_action, NULL); 89 sigprocmask(SIG_SETMASK, &saved_sigset, NULL); 90 alarm(saved_alarm); 91 if (timed_out || ferror(stdin)) 92 return (NULL); 93 /* trim trailing whitespace */ 94 for (len = strlen(buf); len > 0; --len) 95 if (!isspace(buf[len - 1])) 96 break; 97 buf[len] = '\0'; 98 return (strdup(buf)); 99} 100 101static char * 102prompt_echo_off(const char *msg) 103{ 104 struct termios tattr; 105 tcflag_t lflag; 106 char *ret; 107 int fd; 108 109 fd = fileno(stdin); 110 if (tcgetattr(fd, &tattr) != 0) { 111 openpam_log(PAM_LOG_ERROR, "tcgetattr(): %m"); 112 return (NULL); 113 } 114 lflag = tattr.c_lflag; 115 tattr.c_lflag &= ~ECHO; 116 if (tcsetattr(fd, TCSAFLUSH, &tattr) != 0) { 117 openpam_log(PAM_LOG_ERROR, "tcsetattr(): %m"); 118 return (NULL); 119 } 120 ret = prompt(msg); 121 tattr.c_lflag = lflag; 122 (void)tcsetattr(fd, TCSANOW, &tattr); 123 if (ret != NULL) 124 fputs("\n", stdout); 125 return (ret); 126} 127 128/* 129 * OpenPAM extension 130 * 131 * Simple tty-based conversation function 132 */ 133 134int 135openpam_ttyconv(int n, 136 const struct pam_message **msg, 137 struct pam_response **resp, 138 void *data) 139{ 140 int i; 141 142 data = data; 143 if (n <= 0 || n > PAM_MAX_NUM_MSG) 144 return (PAM_CONV_ERR); 145 if ((*resp = calloc(n, sizeof **resp)) == NULL) 146 return (PAM_BUF_ERR); 147 for (i = 0; i < n; ++i) { 148 resp[i]->resp_retcode = 0; 149 resp[i]->resp = NULL; 150 switch (msg[i]->msg_style) { 151 case PAM_PROMPT_ECHO_OFF: 152 resp[i]->resp = prompt_echo_off(msg[i]->msg); 153 if (resp[i]->resp == NULL) 154 goto fail; 155 break; 156 case PAM_PROMPT_ECHO_ON: 157 resp[i]->resp = prompt(msg[i]->msg); 158 if (resp[i]->resp == NULL) 159 goto fail; 160 break; 161 case PAM_ERROR_MSG: 162 fputs(msg[i]->msg, stderr); 163 if (strlen(msg[i]->msg) > 0 && 164 msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n') 165 fputc('\n', stderr); 166 break; 167 case PAM_TEXT_INFO: 168 fputs(msg[i]->msg, stdout); 169 if (strlen(msg[i]->msg) > 0 && 170 msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n') 171 fputc('\n', stdout); 172 break; 173 default: 174 goto fail; 175 } 176 } 177 return (PAM_SUCCESS); 178 fail: 179 while (i) 180 free(resp[--i]); 181 free(*resp); 182 *resp = NULL; 183 return (PAM_CONV_ERR); 184} 185 186/* 187 * NOLIST 188 * 189 * Error codes: 190 * 191 * PAM_SYSTEM_ERR 192 * PAM_BUF_ERR 193 * PAM_CONV_ERR 194 */ 195 196/** 197 * The =openpam_ttyconv function is a standard conversation function 198 * suitable for use on TTY devices. It should be adequate for the needs 199 * of most text-based interactive programs. 200 * 201 * The =openpam_ttyconv function allows the application to specify a 202 * timeout for user input by setting the global variable 203 * :openpam_ttyconv_timeout to the length of the timeout in seconds. 204 * 205 * >openpam_nullconv 206 * >pam_prompt 207 * >pam_vprompt 208 */ 209