Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.2
1.1 millert 1: /*
2: * Copyright (c) 1996, 1998, 1999 Todd C. Miller <Todd.Miller@courtesan.com>
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: *
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: *
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * 3. The name of the author may not be used to endorse or promote products
17: * derived from this software without specific prior written permission.
18: *
19: * 4. Products derived from this software may not be called "Sudo" nor
20: * may "Sudo" appear in their names without specific prior written
21: * permission from the author.
22: *
23: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include "config.h"
36:
37: #include <stdio.h>
38: #ifdef STDC_HEADERS
39: #include <stdlib.h>
40: #endif /* STDC_HEADERS */
41: #ifdef HAVE_UNISTD_H
42: #include <unistd.h>
43: #endif /* HAVE_UNISTD_H */
44: #ifdef HAVE_STRING_H
45: #include <string.h>
46: #endif /* HAVE_STRING_H */
47: #ifdef HAVE_STRINGS_H
48: #include <strings.h>
49: #endif /* HAVE_STRINGS_H */
50: #include <pwd.h>
51: #include <sys/param.h>
52: #include <sys/types.h>
53: #ifdef HAVE_SYS_BSDTYPES_H
54: #include <sys/bsdtypes.h>
55: #endif /* HAVE_SYS_BSDTYPES_H */
56: #ifdef HAVE_SYS_SELECT_H
57: #include <sys/select.h>
58: #endif /* HAVE_SYS_SELECT_H */
59: #include <sys/time.h>
60: #include <errno.h>
61: #include <signal.h>
62: #include <fcntl.h>
63: #ifdef HAVE_TERMIOS_H
64: #include <termios.h>
65: #else
66: #ifdef HAVE_TERMIO_H
67: #include <termio.h>
68: #else
69: #include <sgtty.h>
70: #include <sys/ioctl.h>
71: #endif /* HAVE_TERMIO_H */
72: #endif /* HAVE_TERMIOS_H */
73:
74: #include "sudo.h"
75:
76: #ifndef TCSASOFT
77: #define TCSASOFT 0
78: #endif /* TCSASOFT */
79:
80: #ifndef lint
1.2 ! millert 81: static const char rcsid[] = "$Sudo: tgetpass.c,v 1.91 1999/12/05 02:18:47 millert Exp $";
1.1 millert 82: #endif /* lint */
83:
84: static char *tgetline __P((int, char *, size_t, int));
85:
86: /*
87: * Like getpass(3) but with timeout and echo flags.
88: */
89: char *
90: tgetpass(prompt, timeout, echo_off)
91: const char *prompt;
92: int timeout;
93: int echo_off;
94: {
95: #ifdef HAVE_TERMIOS_H
96: struct termios term;
97: #else
98: #ifdef HAVE_TERMIO_H
99: struct termio term;
100: #else
101: struct sgttyb ttyb;
102: #endif /* HAVE_TERMIO_H */
103: #endif /* HAVE_TERMIOS_H */
104: int input, output;
105: static char buf[SUDO_PASS_MAX + 1];
106:
107: /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */
108: if ((input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
109: input = STDIN_FILENO;
110: output = STDERR_FILENO;
111: }
112:
113: if (prompt)
114: (void) write(output, prompt, strlen(prompt) + 1);
115:
116: if (echo_off) {
117: #ifdef HAVE_TERMIOS_H
118: (void) tcgetattr(input, &term);
119: if ((echo_off = (term.c_lflag & ECHO))) {
120: term.c_lflag &= ~ECHO;
121: (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
122: }
123: #else
124: #ifdef HAVE_TERMIO_H
125: (void) ioctl(input, TCGETA, &term);
126: if ((echo_off = (term.c_lflag & ECHO))) {
127: term.c_lflag &= ~ECHO;
128: (void) ioctl(input, TCSETA, &term);
129: }
130: #else
131: (void) ioctl(input, TIOCGETP, &ttyb);
132: if ((echo_off = (ttyb.sg_flags & ECHO))) {
133: ttyb.sg_flags &= ~ECHO;
134: (void) ioctl(input, TIOCSETP, &ttyb);
135: }
136: #endif /* HAVE_TERMIO_H */
137: #endif /* HAVE_TERMIOS_H */
138: }
139:
140: buf[0] = '\0';
141: tgetline(input, buf, sizeof(buf), timeout);
142:
143: #ifdef HAVE_TERMIOS_H
144: if (echo_off) {
145: term.c_lflag |= ECHO;
146: (void) tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
147: }
148: #else
149: #ifdef HAVE_TERMIO_H
150: if (echo_off) {
151: term.c_lflag |= ECHO;
152: (void) ioctl(input, TCSETA, &term);
153: }
154: #else
155: if (echo_off) {
156: ttyb.sg_flags |= ECHO;
157: (void) ioctl(input, TIOCSETP, &ttyb);
158: }
159: #endif /* HAVE_TERMIO_H */
160: #endif /* HAVE_TERMIOS_H */
161:
162: if (echo_off)
163: (void) write(output, "\n", 1);
164:
165: if (input != STDIN_FILENO)
166: (void) close(input);
167:
168: return(buf);
169: }
170:
171: /*
172: * Get a line of input (optionally timing out) and place it in buf.
173: */
174: static char *
175: tgetline(fd, buf, bufsiz, timeout)
176: int fd;
177: char *buf;
178: size_t bufsiz;
179: int timeout;
180: {
181: size_t left;
182: int n;
183: fd_set *readfds = NULL;
184: struct timeval tv;
185: char c;
186: char *cp;
187:
188: if (bufsiz == 0)
189: return(NULL); /* sanity */
190:
1.2 ! millert 191: cp = buf;
! 192: left = bufsiz;
! 193:
1.1 millert 194: /*
195: * Timeout of <= 0 means no timeout.
196: */
197: if (timeout > 0) {
198: /* Setup for select(2) */
199: n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask);
200: readfds = (fd_set *) emalloc(n);
201: (void) memset((VOID *)readfds, 0, n);
202:
203: /* Set timeout for select */
204: tv.tv_sec = timeout;
205: tv.tv_usec = 0;
206:
1.2 ! millert 207: while (--left) {
! 208: FD_SET(fd, readfds);
! 209:
! 210: /* Make sure there is something to read (or timeout) */
! 211: while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
! 212: errno == EINTR)
! 213: ;
! 214: if (n == 0)
! 215: return(NULL); /* timeout */
! 216:
! 217: /* Read a character, exit loop on error, EOF or EOL */
! 218: n = read(fd, &c, 1);
! 219: if (n != 1 || c == '\n')
! 220: break;
! 221: *cp++ = c;
! 222: }
! 223: free(readfds);
! 224: } else {
! 225: /* Keep reading until out of space, EOF, error, or newline */
! 226: while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n')
! 227: *cp++ = c;
1.1 millert 228: }
229: *cp = '\0';
230:
231: return(cp == buf ? NULL : buf);
232: }