Annotation of src/usr.bin/sudo/tgetpass.c, Revision 1.1.1.1
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
81: static const char rcsid[] = "$Sudo: tgetpass.c,v 1.90 1999/11/01 15:58:46 millert Exp $";
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:
191: /*
192: * Timeout of <= 0 means no timeout.
193: */
194: if (timeout > 0) {
195: /* Setup for select(2) */
196: n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask);
197: readfds = (fd_set *) emalloc(n);
198: (void) memset((VOID *)readfds, 0, n);
199: FD_SET(fd, readfds);
200:
201: /* Set timeout for select */
202: tv.tv_sec = timeout;
203: tv.tv_usec = 0;
204:
205: /*
206: * Make sure there is something to read or timeout
207: */
208: while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 &&
209: errno == EINTR)
210: ;
211: if (n == 0)
212: return(NULL); /* timeout */
213: }
214: if (readfds)
215: free(readfds);
216:
217: /* Keep reading until out of space, EOF, error, or newline */
218: cp = buf;
219: left = bufsiz;
220: while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n')
221: *cp++ = c;
222: *cp = '\0';
223:
224: return(cp == buf ? NULL : buf);
225: }