]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/screenlock.c
e6ea2c88b8b76d90bbb69e898f2e86939bc63712
[plan9front.git] / sys / src / cmd / screenlock.c
1 /* screenlock - lock a terminal */
2 #include <u.h>
3 #include <libc.h>
4 #include <libsec.h>
5 #include <draw.h>
6 #include <thread.h>
7 #include <auth.h>
8
9 char pic[] = "/lib/bunny.bit";
10
11 int debug;
12 int doblank;
13 int chatty = 0;
14
15 char user[256];
16
17 void
18 error(char *fmt, ...)
19 {
20         Fmt f;
21         char buf[64];
22         va_list arg;
23
24         fmtfdinit(&f, 1, buf, sizeof buf);
25         fmtprint(&f, "screenlock: ");
26         va_start(arg, fmt);
27         fmtvprint(&f, fmt, arg);
28         va_end(arg);
29         fmtprint(&f, "\n");
30         fmtfdflush(&f);
31         threadexitsall("fatal error");
32 }
33
34 void
35 usage(void)
36 {
37         fprint(2, "usage: %s\n", argv0);
38         exits("usage");
39 }
40
41
42 void
43 readfile(char *name, char *buf, int nbuf, int addnul)
44 {
45         int fd;
46
47         fd = open(name, OREAD);
48         if(fd == -1)
49                 error("%s - can't open: %r", name);
50         nbuf = read(fd, buf, nbuf-addnul);
51         close(fd);
52         if(nbuf == -1)
53                 error("%s - can't can't read: %r", name);
54         if(addnul)
55                 buf[nbuf] = '\0';
56 }
57
58 void
59 readline(char *buf, int nbuf)
60 {
61         char c;
62         int i;
63
64         i = 0;
65         while(i < nbuf-1)
66                 if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){
67                         i = 0;
68                         break;
69                 } else if(c == '\n')
70                         break;
71                 else if(c == '\b' && i > 0)
72                         --i;
73                 else if(c == ('u' & 037))
74                         i = 0;
75                 else
76                         buf[i++] = c;
77         buf[i] = '\0';
78 }
79
80 void
81 checkpassword(void)
82 {
83         int fd, consctl, must;
84         char buf[256];
85         AuthInfo *ai;
86         static int opened;
87
88         must = 1;
89         if(!opened){
90                 fd = open("/dev/cons", OREAD);
91                 if(fd == -1)
92                         error("can't open cons: %r");
93                 dup(fd, 0);
94                 close(fd);
95                 fd = open("/dev/cons", OWRITE);
96                 if(fd == -1)
97                         error("can't open cons: %r");
98                 dup(fd, 1);
99                 dup(1, 2);
100                 close(fd);
101                 consctl = open("/dev/consctl", OWRITE);
102                 if(consctl == -1)
103                         error("can't open consctl: %r");
104                 if(write(consctl, "rawon", 5) != 5)
105                         error("can't turn off echo\n");
106                 opened = 1;
107         }
108
109         for(;;){
110                 if(chatty || !must)
111                         fprint(2, "%s's screenlock password: ", user);
112                 memset(buf, 0, sizeof buf);
113                 readline(buf, sizeof buf);
114                 if(chatty || !must)
115                         fprint(2, "\n");
116                 if(buf[0] == '\0' || buf[0] == '\04'){
117                         if(must)
118                                 continue;
119                         error("no password typed");
120                 }
121
122                 /* authenticate */
123                 ai = auth_userpasswd(user, buf);
124                 if(ai != nil && ai->cap != nil)
125                         break;
126                 auth_freeAI(ai);
127
128                 if(chatty || !must)
129                         fprint(2, "password mismatch\n");
130                 doblank = 1;
131         }
132         memset(buf, 0, sizeof buf);
133 }
134
135 void
136 blanker(void *)
137 {
138         int fd, tics;
139
140         fd = open("/dev/mousectl", OWRITE);
141         if(fd < 0)
142                 return;
143         tics = 0;
144         for(;;){
145                 if(doblank > 0){
146                         doblank = 0;
147                         tics = 10;
148                 }
149                 if(tics > 0 && --tics == 0)
150                         write(fd, "blank", 5);
151                 sleep(1000);
152         }
153 }
154
155 void
156 grabmouse(void*)
157 {
158         int fd, x, y;
159         char ibuf[256], obuf[256];
160
161         if(debug)
162                 return;
163         fd = open("/dev/mouse", ORDWR);
164         if(fd < 0)
165                 error("can't open /dev/mouse: %r");
166
167         snprint(obuf, sizeof obuf, "m %d %d",
168                 screen->r.min.x + Dx(screen->r)/2,
169                 screen->r.min.y + Dy(screen->r)/2);
170         while(read(fd, ibuf, sizeof ibuf) > 0){
171                 ibuf[12] = 0;
172                 ibuf[24] = 0;
173                 x = atoi(ibuf+1);
174                 y = atoi(ibuf+13);
175                 if(x != screen->r.min.x + Dx(screen->r)/2 ||
176                    y != screen->r.min.y + Dy(screen->r)/2){
177                         fprint(fd, "%s", obuf);
178                         doblank = 1;
179                 }
180         }
181 }
182
183 /* lay down text at `p' */
184 static void
185 screenstring(Point p, char *s)
186 {
187         string(screen, p, screen->display->white, ZP, font, s);
188         flushimage(display, 1);
189 }
190
191 void
192 lockscreen(void)
193 {
194         enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, };
195         char *s;
196         char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen];
197         int fd, dx, dy;
198         Image *i;
199         Point p;
200         Rectangle r;
201         Tm *tm;
202
203         fd = open("/dev/screen", OREAD);
204         if(fd < 0)
205                 error("can't open /dev/screen: %r");
206         if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen)
207                 error("can't read /dev/screen: %r");
208         close(fd);
209         buf[sizeof buf-1] = 0;
210         if(tokenize(buf, flds, Nfld) != Nfld)
211                 error("can't tokenize /dev/screen header");
212         snprint(newcmd, sizeof newcmd, "-r %s %s %d %d",
213                 flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1);
214         newwindow(newcmd);
215         if (initdraw(nil, nil, "screenlock") < 0)
216                 sysfatal("initdraw failed");
217         if(display == nil)
218                 error("no display");
219
220         /* screen is now open and covered.  grab mouse and hold on tight */
221         procrfork(grabmouse, nil, 4096, RFFDG);
222         procrfork(blanker, nil, 4096, RFFDG);
223         fd = open(pic, OREAD);
224         if(fd > 0){
225                 i = readimage(display, fd, 0);
226                 if(i){
227                         r = screen->r;
228                         p = Pt(r.max.x / 2, r.max.y * 2 / 3); 
229                         dx = (Dx(screen->r) - Dx(i->r)) / 2;
230                         r.min.x += dx;
231                         r.max.x -= dx;
232                         dy = (Dy(screen->r) - Dy(i->r)) / 2;
233                         r.min.y += dy;
234                         r.max.y -= dy;
235                         draw(screen, screen->r, display->black, nil, ZP);
236                         draw(screen, r, i, nil, i->r.min);
237                         flushimage(display, 1);
238                 }
239                 close(fd);
240
241                 /* identify the user on screen, centered */
242                 tm = localtime(time(0));
243                 s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min);
244                 p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0));
245                 screenstring(p, s);
246         }
247
248         /* clear the cursor */
249         fd = open("/dev/cursor", OWRITE);
250         if(fd > 0){
251                 memset(cbuf, 0, sizeof cbuf);
252                 write(fd, cbuf, sizeof cbuf);
253                 /* leave it open */
254         }
255 }
256
257 void
258 threadmain(int argc, char *argv[])
259 {
260         readfile("#c/user", user, sizeof user, 1);
261         ARGBEGIN{
262         case 'd':
263                 debug++;
264                 break;
265         default:
266                 usage();
267         }ARGEND
268
269         if(argc != 0)
270                 usage();
271
272         doblank = 1;
273         lockscreen();
274         checkpassword();
275         threadexitsall(nil);
276 }