1f7e6344dSDag-Erling Smørgrav /*- 2f7e6344dSDag-Erling Smørgrav * Copyright (c) 2002-2003 Networks Associates Technology, Inc. 3f7e6344dSDag-Erling Smørgrav * Copyright (c) 2004-2011 Dag-Erling Smørgrav 4f7e6344dSDag-Erling Smørgrav * All rights reserved. 5f7e6344dSDag-Erling Smørgrav * 6f7e6344dSDag-Erling Smørgrav * This software was developed for the FreeBSD Project by ThinkSec AS and 7f7e6344dSDag-Erling Smørgrav * Network Associates Laboratories, the Security Research Division of 8f7e6344dSDag-Erling Smørgrav * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 9f7e6344dSDag-Erling Smørgrav * ("CBOSS"), as part of the DARPA CHATS research program. 10f7e6344dSDag-Erling Smørgrav * 11f7e6344dSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 12f7e6344dSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 13f7e6344dSDag-Erling Smørgrav * are met: 14f7e6344dSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 15f7e6344dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 16f7e6344dSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 17f7e6344dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 18f7e6344dSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 19f7e6344dSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote 20f7e6344dSDag-Erling Smørgrav * products derived from this software without specific prior written 21f7e6344dSDag-Erling Smørgrav * permission. 22f7e6344dSDag-Erling Smørgrav * 23f7e6344dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24f7e6344dSDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25f7e6344dSDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26f7e6344dSDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27f7e6344dSDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28f7e6344dSDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29f7e6344dSDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30f7e6344dSDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31f7e6344dSDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32f7e6344dSDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33f7e6344dSDag-Erling Smørgrav * SUCH DAMAGE. 34f7e6344dSDag-Erling Smørgrav * 35*d64f4044SDag-Erling Smørgrav * $Id: openpam_ttyconv.c 807 2014-09-09 09:41:32Z des $ 36f7e6344dSDag-Erling Smørgrav */ 37f7e6344dSDag-Erling Smørgrav 38f7e6344dSDag-Erling Smørgrav #ifdef HAVE_CONFIG_H 39f7e6344dSDag-Erling Smørgrav # include "config.h" 40f7e6344dSDag-Erling Smørgrav #endif 41f7e6344dSDag-Erling Smørgrav 42f7e6344dSDag-Erling Smørgrav #include <sys/types.h> 43ce77a8d6SDag-Erling Smørgrav #include <sys/poll.h> 44ce77a8d6SDag-Erling Smørgrav #include <sys/time.h> 45f7e6344dSDag-Erling Smørgrav 46f7e6344dSDag-Erling Smørgrav #include <errno.h> 47ce77a8d6SDag-Erling Smørgrav #include <fcntl.h> 48f7e6344dSDag-Erling Smørgrav #include <signal.h> 49f7e6344dSDag-Erling Smørgrav #include <stdio.h> 50f7e6344dSDag-Erling Smørgrav #include <stdlib.h> 51f7e6344dSDag-Erling Smørgrav #include <string.h> 52f7e6344dSDag-Erling Smørgrav #include <termios.h> 53f7e6344dSDag-Erling Smørgrav #include <unistd.h> 54f7e6344dSDag-Erling Smørgrav 55f7e6344dSDag-Erling Smørgrav #include <security/pam_appl.h> 56f7e6344dSDag-Erling Smørgrav 57f7e6344dSDag-Erling Smørgrav #include "openpam_impl.h" 58*d64f4044SDag-Erling Smørgrav #include "openpam_strlset.h" 59f7e6344dSDag-Erling Smørgrav 60f7e6344dSDag-Erling Smørgrav int openpam_ttyconv_timeout = 0; 61f7e6344dSDag-Erling Smørgrav 62ce77a8d6SDag-Erling Smørgrav static volatile sig_atomic_t caught_signal; 63ce77a8d6SDag-Erling Smørgrav 64ce77a8d6SDag-Erling Smørgrav /* 65ce77a8d6SDag-Erling Smørgrav * Handle incoming signals during tty conversation 66ce77a8d6SDag-Erling Smørgrav */ 67f7e6344dSDag-Erling Smørgrav static void 68ce77a8d6SDag-Erling Smørgrav catch_signal(int signo) 69f7e6344dSDag-Erling Smørgrav { 70f7e6344dSDag-Erling Smørgrav 71ce77a8d6SDag-Erling Smørgrav switch (signo) { 72ce77a8d6SDag-Erling Smørgrav case SIGINT: 73ce77a8d6SDag-Erling Smørgrav case SIGQUIT: 74ce77a8d6SDag-Erling Smørgrav case SIGTERM: 75ce77a8d6SDag-Erling Smørgrav caught_signal = signo; 76ce77a8d6SDag-Erling Smørgrav break; 77ce77a8d6SDag-Erling Smørgrav } 78f7e6344dSDag-Erling Smørgrav } 79f7e6344dSDag-Erling Smørgrav 80ce77a8d6SDag-Erling Smørgrav /* 81ce77a8d6SDag-Erling Smørgrav * Accept a response from the user on a tty 82ce77a8d6SDag-Erling Smørgrav */ 83ce77a8d6SDag-Erling Smørgrav static int 84ce77a8d6SDag-Erling Smørgrav prompt_tty(int ifd, int ofd, const char *message, char *response, int echo) 85f7e6344dSDag-Erling Smørgrav { 86ce77a8d6SDag-Erling Smørgrav struct sigaction action; 87ce77a8d6SDag-Erling Smørgrav struct sigaction saction_sigint, saction_sigquit, saction_sigterm; 88ce77a8d6SDag-Erling Smørgrav struct termios tcattr; 89ce77a8d6SDag-Erling Smørgrav struct timeval now, target, remaining; 90ce77a8d6SDag-Erling Smørgrav int remaining_ms; 91ce77a8d6SDag-Erling Smørgrav tcflag_t slflag; 92ce77a8d6SDag-Erling Smørgrav struct pollfd pfd; 93ce77a8d6SDag-Erling Smørgrav int serrno; 94ce77a8d6SDag-Erling Smørgrav int pos, ret; 95f7e6344dSDag-Erling Smørgrav char ch; 96f7e6344dSDag-Erling Smørgrav 97ce77a8d6SDag-Erling Smørgrav /* write prompt */ 98ce77a8d6SDag-Erling Smørgrav if (write(ofd, message, strlen(message)) < 0) { 99ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "write(): %m"); 100ce77a8d6SDag-Erling Smørgrav return (-1); 101ce77a8d6SDag-Erling Smørgrav } 102ce77a8d6SDag-Erling Smørgrav 103ce77a8d6SDag-Erling Smørgrav /* turn echo off if requested */ 104ce77a8d6SDag-Erling Smørgrav slflag = 0; /* prevent bogus uninitialized variable warning */ 105ce77a8d6SDag-Erling Smørgrav if (!echo) { 106ce77a8d6SDag-Erling Smørgrav if (tcgetattr(ifd, &tcattr) != 0) { 107ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "tcgetattr(): %m"); 108ce77a8d6SDag-Erling Smørgrav return (-1); 109ce77a8d6SDag-Erling Smørgrav } 110ce77a8d6SDag-Erling Smørgrav slflag = tcattr.c_lflag; 111ce77a8d6SDag-Erling Smørgrav tcattr.c_lflag &= ~ECHO; 112ce77a8d6SDag-Erling Smørgrav if (tcsetattr(ifd, TCSAFLUSH, &tcattr) != 0) { 113ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "tcsetattr(): %m"); 114ce77a8d6SDag-Erling Smørgrav return (-1); 115ce77a8d6SDag-Erling Smørgrav } 116ce77a8d6SDag-Erling Smørgrav } 117ce77a8d6SDag-Erling Smørgrav 118ce77a8d6SDag-Erling Smørgrav /* install signal handlers */ 119ce77a8d6SDag-Erling Smørgrav caught_signal = 0; 120ce77a8d6SDag-Erling Smørgrav action.sa_handler = &catch_signal; 121f7e6344dSDag-Erling Smørgrav action.sa_flags = 0; 122ce77a8d6SDag-Erling Smørgrav sigfillset(&action.sa_mask); 123ce77a8d6SDag-Erling Smørgrav sigaction(SIGINT, &action, &saction_sigint); 124ce77a8d6SDag-Erling Smørgrav sigaction(SIGQUIT, &action, &saction_sigquit); 125ce77a8d6SDag-Erling Smørgrav sigaction(SIGTERM, &action, &saction_sigterm); 126ce77a8d6SDag-Erling Smørgrav 127ce77a8d6SDag-Erling Smørgrav /* compute timeout */ 128ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) { 129ce77a8d6SDag-Erling Smørgrav (void)gettimeofday(&now, NULL); 130ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = openpam_ttyconv_timeout; 131ce77a8d6SDag-Erling Smørgrav remaining.tv_usec = 0; 132ce77a8d6SDag-Erling Smørgrav timeradd(&now, &remaining, &target); 133ce77a8d6SDag-Erling Smørgrav } else { 134ce77a8d6SDag-Erling Smørgrav /* prevent bogus uninitialized variable warning */ 135ce77a8d6SDag-Erling Smørgrav now.tv_sec = now.tv_usec = 0; 136ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = remaining.tv_usec = 0; 137ce77a8d6SDag-Erling Smørgrav target.tv_sec = target.tv_usec = 0; 138ce77a8d6SDag-Erling Smørgrav } 139ce77a8d6SDag-Erling Smørgrav 140ce77a8d6SDag-Erling Smørgrav /* input loop */ 141ce77a8d6SDag-Erling Smørgrav pos = 0; 142ce77a8d6SDag-Erling Smørgrav ret = -1; 143ce77a8d6SDag-Erling Smørgrav serrno = 0; 144ce77a8d6SDag-Erling Smørgrav while (!caught_signal) { 145ce77a8d6SDag-Erling Smørgrav pfd.fd = ifd; 146ce77a8d6SDag-Erling Smørgrav pfd.events = POLLIN; 147ce77a8d6SDag-Erling Smørgrav pfd.revents = 0; 148ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) { 149ce77a8d6SDag-Erling Smørgrav gettimeofday(&now, NULL); 150ce77a8d6SDag-Erling Smørgrav if (timercmp(&now, &target, >)) 151ce77a8d6SDag-Erling Smørgrav break; 152ce77a8d6SDag-Erling Smørgrav timersub(&target, &now, &remaining); 153ce77a8d6SDag-Erling Smørgrav remaining_ms = remaining.tv_sec * 1000 + 154ce77a8d6SDag-Erling Smørgrav remaining.tv_usec / 1000; 155ce77a8d6SDag-Erling Smørgrav } else { 156ce77a8d6SDag-Erling Smørgrav remaining_ms = -1; 157ce77a8d6SDag-Erling Smørgrav } 158ce77a8d6SDag-Erling Smørgrav if ((ret = poll(&pfd, 1, remaining_ms)) < 0) { 159ce77a8d6SDag-Erling Smørgrav serrno = errno; 160ce77a8d6SDag-Erling Smørgrav if (errno == EINTR) 161ce77a8d6SDag-Erling Smørgrav continue; 162ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "poll(): %m"); 163ce77a8d6SDag-Erling Smørgrav break; 164ce77a8d6SDag-Erling Smørgrav } else if (ret == 0) { 165ce77a8d6SDag-Erling Smørgrav /* timeout */ 166ce77a8d6SDag-Erling Smørgrav write(ofd, " timed out", 10); 167ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_NOTICE, "timed out"); 168ce77a8d6SDag-Erling Smørgrav break; 169ce77a8d6SDag-Erling Smørgrav } 170ce77a8d6SDag-Erling Smørgrav if ((ret = read(ifd, &ch, 1)) < 0) { 171ce77a8d6SDag-Erling Smørgrav serrno = errno; 172ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "read(): %m"); 173ce77a8d6SDag-Erling Smørgrav break; 174ce77a8d6SDag-Erling Smørgrav } else if (ret == 0 || ch == '\n') { 175ce77a8d6SDag-Erling Smørgrav response[pos] = '\0'; 176ce77a8d6SDag-Erling Smørgrav ret = pos; 177ce77a8d6SDag-Erling Smørgrav break; 178ce77a8d6SDag-Erling Smørgrav } 179ce77a8d6SDag-Erling Smørgrav if (pos + 1 < PAM_MAX_RESP_SIZE) 180ce77a8d6SDag-Erling Smørgrav response[pos++] = ch; 181ce77a8d6SDag-Erling Smørgrav /* overflow is discarded */ 182ce77a8d6SDag-Erling Smørgrav } 183ce77a8d6SDag-Erling Smørgrav 184ce77a8d6SDag-Erling Smørgrav /* restore tty state */ 185ce77a8d6SDag-Erling Smørgrav if (!echo) { 186ce77a8d6SDag-Erling Smørgrav tcattr.c_lflag = slflag; 187ce77a8d6SDag-Erling Smørgrav if (tcsetattr(ifd, 0, &tcattr) != 0) { 188ce77a8d6SDag-Erling Smørgrav /* treat as non-fatal, since we have our answer */ 189ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_NOTICE, "tcsetattr(): %m"); 190ce77a8d6SDag-Erling Smørgrav } 191ce77a8d6SDag-Erling Smørgrav } 192ce77a8d6SDag-Erling Smørgrav 193ce77a8d6SDag-Erling Smørgrav /* restore signal handlers and re-post caught signal*/ 194ce77a8d6SDag-Erling Smørgrav sigaction(SIGINT, &saction_sigint, NULL); 195ce77a8d6SDag-Erling Smørgrav sigaction(SIGQUIT, &saction_sigquit, NULL); 196ce77a8d6SDag-Erling Smørgrav sigaction(SIGTERM, &saction_sigterm, NULL); 197ce77a8d6SDag-Erling Smørgrav if (caught_signal != 0) { 198ce77a8d6SDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "caught signal %d", 199ce77a8d6SDag-Erling Smørgrav (int)caught_signal); 200ce77a8d6SDag-Erling Smørgrav raise((int)caught_signal); 201ce77a8d6SDag-Erling Smørgrav /* if raise() had no effect... */ 202ce77a8d6SDag-Erling Smørgrav serrno = EINTR; 203ce77a8d6SDag-Erling Smørgrav ret = -1; 204ce77a8d6SDag-Erling Smørgrav } 205ce77a8d6SDag-Erling Smørgrav 206ce77a8d6SDag-Erling Smørgrav /* done */ 207ce77a8d6SDag-Erling Smørgrav write(ofd, "\n", 1); 208ce77a8d6SDag-Erling Smørgrav errno = serrno; 209ce77a8d6SDag-Erling Smørgrav return (ret); 210ce77a8d6SDag-Erling Smørgrav } 211ce77a8d6SDag-Erling Smørgrav 212ce77a8d6SDag-Erling Smørgrav /* 213ce77a8d6SDag-Erling Smørgrav * Accept a response from the user on a non-tty stdin. 214ce77a8d6SDag-Erling Smørgrav */ 215ce77a8d6SDag-Erling Smørgrav static int 216ce77a8d6SDag-Erling Smørgrav prompt_notty(const char *message, char *response) 217ce77a8d6SDag-Erling Smørgrav { 218ce77a8d6SDag-Erling Smørgrav struct timeval now, target, remaining; 219ce77a8d6SDag-Erling Smørgrav int remaining_ms; 220ce77a8d6SDag-Erling Smørgrav struct pollfd pfd; 221ce77a8d6SDag-Erling Smørgrav int ch, pos, ret; 222ce77a8d6SDag-Erling Smørgrav 223ce77a8d6SDag-Erling Smørgrav /* show prompt */ 224ce77a8d6SDag-Erling Smørgrav fputs(message, stdout); 225ce77a8d6SDag-Erling Smørgrav fflush(stdout); 226ce77a8d6SDag-Erling Smørgrav 227ce77a8d6SDag-Erling Smørgrav /* compute timeout */ 228ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) { 229ce77a8d6SDag-Erling Smørgrav (void)gettimeofday(&now, NULL); 230ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = openpam_ttyconv_timeout; 231ce77a8d6SDag-Erling Smørgrav remaining.tv_usec = 0; 232ce77a8d6SDag-Erling Smørgrav timeradd(&now, &remaining, &target); 233ce77a8d6SDag-Erling Smørgrav } else { 234ce77a8d6SDag-Erling Smørgrav /* prevent bogus uninitialized variable warning */ 235ce77a8d6SDag-Erling Smørgrav now.tv_sec = now.tv_usec = 0; 236ce77a8d6SDag-Erling Smørgrav remaining.tv_sec = remaining.tv_usec = 0; 237ce77a8d6SDag-Erling Smørgrav target.tv_sec = target.tv_usec = 0; 238ce77a8d6SDag-Erling Smørgrav } 239ce77a8d6SDag-Erling Smørgrav 240ce77a8d6SDag-Erling Smørgrav /* input loop */ 241ce77a8d6SDag-Erling Smørgrav pos = 0; 242ce77a8d6SDag-Erling Smørgrav for (;;) { 243ce77a8d6SDag-Erling Smørgrav pfd.fd = STDIN_FILENO; 244ce77a8d6SDag-Erling Smørgrav pfd.events = POLLIN; 245ce77a8d6SDag-Erling Smørgrav pfd.revents = 0; 246ce77a8d6SDag-Erling Smørgrav if (openpam_ttyconv_timeout > 0) { 247ce77a8d6SDag-Erling Smørgrav gettimeofday(&now, NULL); 248ce77a8d6SDag-Erling Smørgrav if (timercmp(&now, &target, >)) 249ce77a8d6SDag-Erling Smørgrav break; 250ce77a8d6SDag-Erling Smørgrav timersub(&target, &now, &remaining); 251ce77a8d6SDag-Erling Smørgrav remaining_ms = remaining.tv_sec * 1000 + 252ce77a8d6SDag-Erling Smørgrav remaining.tv_usec / 1000; 253ce77a8d6SDag-Erling Smørgrav } else { 254ce77a8d6SDag-Erling Smørgrav remaining_ms = -1; 255ce77a8d6SDag-Erling Smørgrav } 256ce77a8d6SDag-Erling Smørgrav if ((ret = poll(&pfd, 1, remaining_ms)) < 0) { 257ce77a8d6SDag-Erling Smørgrav /* interrupt is ok, everything else -> bail */ 258ce77a8d6SDag-Erling Smørgrav if (errno == EINTR) 259ce77a8d6SDag-Erling Smørgrav continue; 260ce77a8d6SDag-Erling Smørgrav perror("\nopenpam_ttyconv"); 261ce77a8d6SDag-Erling Smørgrav return (-1); 262ce77a8d6SDag-Erling Smørgrav } else if (ret == 0) { 263ce77a8d6SDag-Erling Smørgrav /* timeout */ 264ce77a8d6SDag-Erling Smørgrav break; 265ce77a8d6SDag-Erling Smørgrav } else { 266ce77a8d6SDag-Erling Smørgrav /* input */ 267ce77a8d6SDag-Erling Smørgrav if ((ch = getchar()) == EOF && ferror(stdin)) { 268ce77a8d6SDag-Erling Smørgrav perror("\nopenpam_ttyconv"); 269ce77a8d6SDag-Erling Smørgrav return (-1); 270ce77a8d6SDag-Erling Smørgrav } 271ce77a8d6SDag-Erling Smørgrav if (ch == EOF || ch == '\n') { 272ce77a8d6SDag-Erling Smørgrav response[pos] = '\0'; 273ce77a8d6SDag-Erling Smørgrav return (pos); 274ce77a8d6SDag-Erling Smørgrav } 275ce77a8d6SDag-Erling Smørgrav if (pos + 1 < PAM_MAX_RESP_SIZE) 276ce77a8d6SDag-Erling Smørgrav response[pos++] = ch; 277ce77a8d6SDag-Erling Smørgrav /* overflow is discarded */ 278ce77a8d6SDag-Erling Smørgrav } 279ce77a8d6SDag-Erling Smørgrav } 280ce77a8d6SDag-Erling Smørgrav fputs("\nopenpam_ttyconv: timeout\n", stderr); 281ce77a8d6SDag-Erling Smørgrav return (-1); 282ce77a8d6SDag-Erling Smørgrav } 283ce77a8d6SDag-Erling Smørgrav 284ce77a8d6SDag-Erling Smørgrav /* 285ce77a8d6SDag-Erling Smørgrav * Determine whether stdin is a tty; if not, try to open the tty; in 286ce77a8d6SDag-Erling Smørgrav * either case, call the appropriate method. 287ce77a8d6SDag-Erling Smørgrav */ 288ce77a8d6SDag-Erling Smørgrav static int 289ce77a8d6SDag-Erling Smørgrav prompt(const char *message, char *response, int echo) 290ce77a8d6SDag-Erling Smørgrav { 291ce77a8d6SDag-Erling Smørgrav int ifd, ofd, ret; 292ce77a8d6SDag-Erling Smørgrav 293ce77a8d6SDag-Erling Smørgrav if (isatty(STDIN_FILENO)) { 294f7e6344dSDag-Erling Smørgrav fflush(stdout); 295f7e6344dSDag-Erling Smørgrav #ifdef HAVE_FPURGE 296f7e6344dSDag-Erling Smørgrav fpurge(stdin); 297f7e6344dSDag-Erling Smørgrav #endif 298ce77a8d6SDag-Erling Smørgrav ifd = STDIN_FILENO; 299ce77a8d6SDag-Erling Smørgrav ofd = STDOUT_FILENO; 300ce77a8d6SDag-Erling Smørgrav } else { 301ce77a8d6SDag-Erling Smørgrav if ((ifd = open("/dev/tty", O_RDWR)) < 0) 302ce77a8d6SDag-Erling Smørgrav /* no way to prevent echo */ 303ce77a8d6SDag-Erling Smørgrav return (prompt_notty(message, response)); 304ce77a8d6SDag-Erling Smørgrav ofd = ifd; 305f7e6344dSDag-Erling Smørgrav } 306ce77a8d6SDag-Erling Smørgrav ret = prompt_tty(ifd, ofd, message, response, echo); 307ce77a8d6SDag-Erling Smørgrav if (ifd != STDIN_FILENO) 308ce77a8d6SDag-Erling Smørgrav close(ifd); 309f7e6344dSDag-Erling Smørgrav return (ret); 310f7e6344dSDag-Erling Smørgrav } 311f7e6344dSDag-Erling Smørgrav 312f7e6344dSDag-Erling Smørgrav /* 313f7e6344dSDag-Erling Smørgrav * OpenPAM extension 314f7e6344dSDag-Erling Smørgrav * 315f7e6344dSDag-Erling Smørgrav * Simple tty-based conversation function 316f7e6344dSDag-Erling Smørgrav */ 317f7e6344dSDag-Erling Smørgrav 318f7e6344dSDag-Erling Smørgrav int 319f7e6344dSDag-Erling Smørgrav openpam_ttyconv(int n, 320f7e6344dSDag-Erling Smørgrav const struct pam_message **msg, 321f7e6344dSDag-Erling Smørgrav struct pam_response **resp, 322f7e6344dSDag-Erling Smørgrav void *data) 323f7e6344dSDag-Erling Smørgrav { 324ce77a8d6SDag-Erling Smørgrav char respbuf[PAM_MAX_RESP_SIZE]; 325f7e6344dSDag-Erling Smørgrav struct pam_response *aresp; 326f7e6344dSDag-Erling Smørgrav int i; 327f7e6344dSDag-Erling Smørgrav 328f7e6344dSDag-Erling Smørgrav ENTER(); 329f7e6344dSDag-Erling Smørgrav (void)data; 330f7e6344dSDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG) 331f7e6344dSDag-Erling Smørgrav RETURNC(PAM_CONV_ERR); 332f7e6344dSDag-Erling Smørgrav if ((aresp = calloc(n, sizeof *aresp)) == NULL) 333f7e6344dSDag-Erling Smørgrav RETURNC(PAM_BUF_ERR); 334f7e6344dSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 335f7e6344dSDag-Erling Smørgrav aresp[i].resp_retcode = 0; 336f7e6344dSDag-Erling Smørgrav aresp[i].resp = NULL; 337f7e6344dSDag-Erling Smørgrav switch (msg[i]->msg_style) { 338f7e6344dSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 339ce77a8d6SDag-Erling Smørgrav if (prompt(msg[i]->msg, respbuf, 0) < 0 || 340ce77a8d6SDag-Erling Smørgrav (aresp[i].resp = strdup(respbuf)) == NULL) 341f7e6344dSDag-Erling Smørgrav goto fail; 342f7e6344dSDag-Erling Smørgrav break; 343f7e6344dSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 344ce77a8d6SDag-Erling Smørgrav if (prompt(msg[i]->msg, respbuf, 1) < 0 || 345ce77a8d6SDag-Erling Smørgrav (aresp[i].resp = strdup(respbuf)) == NULL) 346f7e6344dSDag-Erling Smørgrav goto fail; 347f7e6344dSDag-Erling Smørgrav break; 348f7e6344dSDag-Erling Smørgrav case PAM_ERROR_MSG: 349f7e6344dSDag-Erling Smørgrav fputs(msg[i]->msg, stderr); 350f7e6344dSDag-Erling Smørgrav if (strlen(msg[i]->msg) > 0 && 351f7e6344dSDag-Erling Smørgrav msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n') 352f7e6344dSDag-Erling Smørgrav fputc('\n', stderr); 353f7e6344dSDag-Erling Smørgrav break; 354f7e6344dSDag-Erling Smørgrav case PAM_TEXT_INFO: 355f7e6344dSDag-Erling Smørgrav fputs(msg[i]->msg, stdout); 356f7e6344dSDag-Erling Smørgrav if (strlen(msg[i]->msg) > 0 && 357f7e6344dSDag-Erling Smørgrav msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n') 358f7e6344dSDag-Erling Smørgrav fputc('\n', stdout); 359f7e6344dSDag-Erling Smørgrav break; 360f7e6344dSDag-Erling Smørgrav default: 361f7e6344dSDag-Erling Smørgrav goto fail; 362f7e6344dSDag-Erling Smørgrav } 363f7e6344dSDag-Erling Smørgrav } 364f7e6344dSDag-Erling Smørgrav *resp = aresp; 365ce77a8d6SDag-Erling Smørgrav memset(respbuf, 0, sizeof respbuf); 366f7e6344dSDag-Erling Smørgrav RETURNC(PAM_SUCCESS); 367f7e6344dSDag-Erling Smørgrav fail: 368f7e6344dSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 369f7e6344dSDag-Erling Smørgrav if (aresp[i].resp != NULL) { 370*d64f4044SDag-Erling Smørgrav strlset(aresp[i].resp, 0, PAM_MAX_RESP_SIZE); 371f7e6344dSDag-Erling Smørgrav FREE(aresp[i].resp); 372f7e6344dSDag-Erling Smørgrav } 373f7e6344dSDag-Erling Smørgrav } 374f7e6344dSDag-Erling Smørgrav memset(aresp, 0, n * sizeof *aresp); 375f7e6344dSDag-Erling Smørgrav FREE(aresp); 376f7e6344dSDag-Erling Smørgrav *resp = NULL; 377ce77a8d6SDag-Erling Smørgrav memset(respbuf, 0, sizeof respbuf); 378f7e6344dSDag-Erling Smørgrav RETURNC(PAM_CONV_ERR); 379f7e6344dSDag-Erling Smørgrav } 380f7e6344dSDag-Erling Smørgrav 381f7e6344dSDag-Erling Smørgrav /* 382f7e6344dSDag-Erling Smørgrav * Error codes: 383f7e6344dSDag-Erling Smørgrav * 384f7e6344dSDag-Erling Smørgrav * PAM_SYSTEM_ERR 385f7e6344dSDag-Erling Smørgrav * PAM_BUF_ERR 386f7e6344dSDag-Erling Smørgrav * PAM_CONV_ERR 387f7e6344dSDag-Erling Smørgrav */ 388f7e6344dSDag-Erling Smørgrav 389f7e6344dSDag-Erling Smørgrav /** 390f7e6344dSDag-Erling Smørgrav * The =openpam_ttyconv function is a standard conversation function 391f7e6344dSDag-Erling Smørgrav * suitable for use on TTY devices. 392f7e6344dSDag-Erling Smørgrav * It should be adequate for the needs of most text-based interactive 393f7e6344dSDag-Erling Smørgrav * programs. 394f7e6344dSDag-Erling Smørgrav * 395f7e6344dSDag-Erling Smørgrav * The =openpam_ttyconv function allows the application to specify a 396f7e6344dSDag-Erling Smørgrav * timeout for user input by setting the global integer variable 397f7e6344dSDag-Erling Smørgrav * :openpam_ttyconv_timeout to the length of the timeout in seconds. 398f7e6344dSDag-Erling Smørgrav * 399f7e6344dSDag-Erling Smørgrav * >openpam_nullconv 400f7e6344dSDag-Erling Smørgrav * >pam_prompt 401f7e6344dSDag-Erling Smørgrav * >pam_vprompt 402f7e6344dSDag-Erling Smørgrav */ 403