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