Syncronise some build files with busybox-cvs-20030819
[oweals/busybox.git] / loginutils / vlock.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * vlock implementation for busybox
4  *
5  * Copyright (C) 2000 by spoon <spoon@ix.netcom.com>
6  * Written by spoon <spon@ix.netcom.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23
24 /* Shoutz to Michael K. Johnson <johnsonm@redhat.com>, author of the
25  * original vlock.  I snagged a bunch of his code to write this
26  * minimalistic vlock.
27  */
28 /* Fixed by Erik Andersen to do passwords the tinylogin way...
29  * It now works with md5, sha1, etc passwords. */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/vt.h>
34 #include <signal.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <sys/ioctl.h>
40 #include <termios.h>
41
42 #include "busybox.h"
43
44 static struct passwd *pw;
45 static struct vt_mode ovtm;
46 static struct termios oterm;
47 static int vfd;
48 static int o_lock_all = 0;
49
50 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
51 static struct spwd *spw;
52
53 /* getspuid - get a shadow entry by uid */
54 struct spwd *getspuid(uid_t uid)
55 {
56         struct spwd *sp;
57         struct passwd *mypw;
58
59         if ((mypw = getpwuid(getuid())) == NULL) {
60                 return (NULL);
61         }
62         setspent();
63         while ((sp = getspent()) != NULL) {
64                 if (strcmp(mypw->pw_name, sp->sp_namp) == 0)
65                         break;
66         }
67         endspent();
68         return (sp);
69 }
70 #endif
71
72 static void release_vt(int signo)
73 {
74         if (!o_lock_all)
75                 ioctl(vfd, VT_RELDISP, 1);
76         else
77                 ioctl(vfd, VT_RELDISP, 0);
78 }
79
80 static void acquire_vt(int signo)
81 {
82         ioctl(vfd, VT_RELDISP, VT_ACKACQ);
83 }
84
85 static void restore_terminal(void)
86 {
87         ioctl(vfd, VT_SETMODE, &ovtm);
88         tcsetattr(STDIN_FILENO, TCSANOW, &oterm);
89 }
90
91 extern int vlock_main(int argc, char **argv)
92 {
93         sigset_t sig;
94         struct sigaction sa;
95         struct vt_mode vtm;
96         int times = 0;
97         struct termios term;
98
99         if (argc > 2) {
100                 bb_show_usage();
101         }
102
103         if (argc == 2) {
104                 if (strncmp(argv[1], "-a", 2)) {
105                         bb_show_usage();
106                 } else {
107                         o_lock_all = 1;
108                 }
109         }
110
111         if ((pw = getpwuid(getuid())) == NULL) {
112                 bb_error_msg_and_die("no password for uid %d\n", getuid());
113         }
114 #ifdef CONFIG_FEATURE_SHADOWPASSWDS
115         if ((strcmp(pw->pw_passwd, "x") == 0)
116                 || (strcmp(pw->pw_passwd, "*") == 0)) {
117
118                 if ((spw = getspuid(getuid())) == NULL) {
119                         bb_error_msg_and_die("could not read shadow password for uid %d: %s\n",
120                                            getuid(), strerror(errno));
121                 }
122                 if (spw->sp_pwdp) {
123                         pw->pw_passwd = spw->sp_pwdp;
124                 }
125         }
126 #endif                                                  /* CONFIG_FEATURE_SHADOWPASSWDS */
127         if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') {
128                 bb_error_msg_and_die("Account disabled for uid %d\n", getuid());
129         }
130
131         /* we no longer need root privs */
132         setuid(getuid());
133         setgid(getgid());
134
135         if ((vfd = open("/dev/tty", O_RDWR)) < 0) {
136                 bb_error_msg_and_die("/dev/tty");
137         };
138
139         if (ioctl(vfd, VT_GETMODE, &vtm) < 0) {
140                 bb_error_msg_and_die("/dev/tty");
141         };
142
143         /* mask a bunch of signals */
144         sigprocmask(SIG_SETMASK, NULL, &sig);
145         sigdelset(&sig, SIGUSR1);
146         sigdelset(&sig, SIGUSR2);
147         sigaddset(&sig, SIGTSTP);
148         sigaddset(&sig, SIGTTIN);
149         sigaddset(&sig, SIGTTOU);
150         sigaddset(&sig, SIGHUP);
151         sigaddset(&sig, SIGCHLD);
152         sigaddset(&sig, SIGQUIT);
153         sigaddset(&sig, SIGINT);
154
155         sigemptyset(&(sa.sa_mask));
156         sa.sa_flags = SA_RESTART;
157         sa.sa_handler = release_vt;
158         sigaction(SIGUSR1, &sa, NULL);
159         sa.sa_handler = acquire_vt;
160         sigaction(SIGUSR2, &sa, NULL);
161
162         /* need to handle some signals so that we don't get killed by them */
163         sa.sa_handler = SIG_IGN;
164         sigaction(SIGHUP, &sa, NULL);
165         sigaction(SIGQUIT, &sa, NULL);
166         sigaction(SIGINT, &sa, NULL);
167         sigaction(SIGTSTP, &sa, NULL);
168
169         ovtm = vtm;
170         vtm.mode = VT_PROCESS;
171         vtm.relsig = SIGUSR1;
172         vtm.acqsig = SIGUSR2;
173         ioctl(vfd, VT_SETMODE, &vtm);
174
175         tcgetattr(STDIN_FILENO, &oterm);
176         term = oterm;
177         term.c_iflag &= ~BRKINT;
178         term.c_iflag |= IGNBRK;
179         term.c_lflag &= ~ISIG;
180         term.c_lflag &= ~(ECHO | ECHOCTL);
181         tcsetattr(STDIN_FILENO, TCSANOW, &term);
182
183         do {
184                 char *pass, *crypt_pass;
185                 char prompt[100];
186
187                 if (o_lock_all) {
188                         printf("All Virtual Consoles locked.\n");
189                 } else {
190                         printf("This Virtual Console locked.\n");
191                 }
192                 fflush(stdout);
193
194                 snprintf(prompt, 100, "%s's password: ", pw->pw_name);
195
196                 if ((pass = getpass(prompt)) == NULL) {
197                         perror("getpass");
198                         restore_terminal();
199                         exit(1);
200                 }
201
202                 crypt_pass = pw_encrypt(pass, pw->pw_passwd);
203                 if (strncmp(crypt_pass, pw->pw_passwd, sizeof(crypt_pass)) == 0) {
204                         memset(pass, 0, strlen(pass));
205                         memset(crypt_pass, 0, strlen(crypt_pass));
206                         restore_terminal();
207                         return 0;
208                 }
209                 memset(pass, 0, strlen(pass));
210                 memset(crypt_pass, 0, strlen(crypt_pass));
211
212                 if (isatty(STDIN_FILENO) == 0) {
213                         perror("isatty");
214                         restore_terminal();
215                         exit(1);
216                 }
217
218                 sleep(++times);
219                 printf("Password incorrect.\n");
220                 if (times >= 3) {
221                         sleep(15);
222                         times = 2;
223                 }
224         } while (1);
225 }
226
227 /*
228 Local Variables:
229 c-file-style: "linux"
230 c-basic-offset: 4
231 tab-width: 4
232 End:
233 */