s4:objectclass LDB module - fix a comment
[nivanova/samba-autobuild/.git] / lib / replace / getpass.c
1 /* Copyright (C) 1992-1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 3 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, see <http://www.gnu.org/licenses/>.  */
17
18 /* Modified to use with samba by Jeremy Allison, 8th July 1995. */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/wait.h"
23 #include "system/terminal.h"
24 #include "system/passwd.h"
25
26 /*
27  * Define additional missing types
28  */
29 #ifndef HAVE_SIG_ATOMIC_T_TYPE
30 typedef int sig_atomic_t;
31 #endif
32
33 #ifndef SIGCLD
34 #define SIGCLD SIGCHLD
35 #endif
36
37 #ifdef SYSV_TERMIO 
38
39 /* SYSTEM V TERMIO HANDLING */
40
41 static struct termio t;
42
43 #define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
44 #define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
45 #define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
46
47 #ifndef TCSAFLUSH
48 #define TCSAFLUSH 1
49 #endif
50
51 #ifndef TCSANOW
52 #define TCSANOW 0
53 #endif
54
55 static int tcgetattr(int fd, struct termio *_t)
56 {
57         return ioctl(fd, TCGETA, _t);
58 }
59
60 static int tcsetattr(int fd, int flags, struct termio *_t)
61 {
62         if(flags & TCSAFLUSH)
63                 ioctl(fd, TCFLSH, TCIOFLUSH);
64         return ioctl(fd, TCSETS, _t);
65 }
66
67 #elif !defined(TCSAFLUSH)
68
69 /* BSD TERMIO HANDLING */
70
71 static struct sgttyb t;  
72
73 #define ECHO_IS_ON(t) ((t).sg_flags & ECHO)
74 #define TURN_ECHO_OFF(t) ((t).sg_flags &= ~ECHO)
75 #define TURN_ECHO_ON(t) ((t).sg_flags |= ECHO)
76
77 #define TCSAFLUSH 1
78 #define TCSANOW 0
79
80 static int tcgetattr(int fd, struct sgttyb *_t)
81 {
82         return ioctl(fd, TIOCGETP, (char *)_t);
83 }
84
85 static int tcsetattr(int fd, int flags, struct sgttyb *_t)
86 {
87         return ioctl(fd, TIOCSETP, (char *)_t);
88 }
89
90 #else /* POSIX TERMIO HANDLING */
91 #define ECHO_IS_ON(t) ((t).c_lflag & ECHO)
92 #define TURN_ECHO_OFF(t) ((t).c_lflag &= ~ECHO)
93 #define TURN_ECHO_ON(t) ((t).c_lflag |= ECHO)
94
95 static struct termios t;
96 #endif /* SYSV_TERMIO */
97
98 static void catch_signal(int signum, void (*handler)(int ))
99 {
100 #ifdef HAVE_SIGACTION
101         struct sigaction act;
102         struct sigaction oldact;
103
104         memset(&act, 0, sizeof(act));
105
106         act.sa_handler = handler;
107 #ifdef SA_RESTART
108         /*
109          * We *want* SIGALRM to interrupt a system call.
110          */
111         if(signum != SIGALRM)
112                 act.sa_flags = SA_RESTART;
113 #endif
114         sigemptyset(&act.sa_mask);
115         sigaddset(&act.sa_mask,signum);
116         sigaction(signum,&act,&oldact);
117 #else /* !HAVE_SIGACTION */
118         /* FIXME: need to handle sigvec and systems with broken signal() */
119         signal(signum, handler);
120 #endif
121 }
122
123 static sig_atomic_t gotintr;
124 static int in_fd = -1;
125
126 /***************************************************************
127  Signal function to tell us were ^C'ed.
128 ****************************************************************/
129
130 static void gotintr_sig(int signum)
131 {
132         gotintr = 1;
133         if (in_fd != -1)
134                 close(in_fd); /* Safe way to force a return. */
135         in_fd = -1;
136 }
137
138 char *rep_getpass(const char *prompt)
139 {
140         FILE *in, *out;
141         int echo_off;
142         static char buf[256];
143         static size_t bufsize = sizeof(buf);
144         size_t nread;
145
146         /* Catch problematic signals */
147         catch_signal(SIGINT, gotintr_sig);
148
149         /* Try to write to and read from the terminal if we can.
150                 If we can't open the terminal, use stderr and stdin.  */
151
152         in = fopen ("/dev/tty", "w+");
153         if (in == NULL) {
154                 in = stdin;
155                 out = stderr;
156         } else {
157                 out = in;
158         }
159
160         setvbuf(in, NULL, _IONBF, 0);
161
162         /* Turn echoing off if it is on now.  */
163
164         if (tcgetattr (fileno (in), &t) == 0) {
165                 if (ECHO_IS_ON(t)) {
166                         TURN_ECHO_OFF(t);
167                         echo_off = tcsetattr (fileno (in), TCSAFLUSH, &t) == 0;
168                         TURN_ECHO_ON(t);
169                 } else {
170                         echo_off = 0;
171                 }
172         } else {
173                 echo_off = 0;
174         }
175
176         /* Write the prompt.  */
177         fputs(prompt, out);
178         fflush(out);
179
180         /* Read the password.  */
181         buf[0] = 0;
182         if (!gotintr) {
183                 in_fd = fileno(in);
184                 if (fgets(buf, bufsize, in) == NULL) {
185                         buf[0] = 0;
186                 }
187         }
188         nread = strlen(buf);
189         if (nread) {
190                 if (buf[nread - 1] == '\n')
191                         buf[nread - 1] = '\0';
192         }
193
194         /* Restore echoing.  */
195         if (echo_off) {
196                 if (gotintr && in_fd == -1) {
197                         in = fopen ("/dev/tty", "w+");
198                 }
199                 if (in != NULL)
200                         tcsetattr (fileno (in), TCSANOW, &t);
201         }
202
203         fprintf(out, "\n");
204         fflush(out);
205
206         if (in && in != stdin) /* We opened the terminal; now close it.  */
207                 fclose(in);
208
209         /* Catch problematic signals */
210         catch_signal(SIGINT, SIG_DFL);
211
212         if (gotintr) {
213                 printf("Interrupted by signal.\n");
214                 fflush(stdout);
215                 exit(1);
216         }
217         return buf;
218 }