xref: /plan9/sys/src/cmd/screenlock.c (revision 047f1f95aa802225c557b6f2f4b096acb12ebb86)
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