xref: /plan9-contrib/sys/src/cmd/screenlock.c (revision b39189fd423aed869c5cf5189bc504918cff969b)
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
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
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
46 usage(void)
47 {
48 	fprint(2, "usage: %s\n", argv0);
49 	exits("usage");
50 }
51 
52 
53 void
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
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
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
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
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 void
194 lockscreen(void)
195 {
196 	enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, };
197 	char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen];
198 	int fd, dx, dy;
199 	Image *i;
200 	Rectangle r;
201 
202 	fd = open("/dev/screen", OREAD);
203 	if(fd < 0)
204 		error("can't open /dev/screen: %r");
205 	if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen)
206 		error("can't read /dev/screen: %r");
207 	close(fd);
208 	buf[sizeof buf-1] = 0;
209 	if(tokenize(buf, flds, Nfld) != Nfld)
210 		error("can't tokenize /dev/screen header");
211 	snprint(newcmd, sizeof newcmd, "-r %s %s %d %d",
212 		flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1);
213 	newwindow(newcmd);
214 	initdraw(nil, nil, "screenlock");
215 
216 	if(display == nil)
217 		error("no display");
218 
219 	/* screen is now open and covered.  grab mouse and hold on tight */
220 	procrfork(grabmouse, nil, 4096, RFFDG);
221 	procrfork(blanker, nil, 4096, RFFDG);
222 	fd = open(pic, OREAD);
223 	if(fd > 0){
224 		i = readimage(display, fd, 0);
225 		if(i){
226  			r = screen->r;
227 			dx = (Dx(screen->r) - Dx(i->r)) / 2;
228 			r.min.x += dx;
229 			r.max.x -= dx;
230 			dy = (Dy(screen->r) - Dy(i->r)) / 2;
231 			r.min.y += dy;
232 			r.max.y -= dy;
233 			draw(screen, screen->r, display->black, nil, ZP);
234 			draw(screen, r, i, nil, i->r.min);
235 			flushimage(display, 1);
236 		}
237 		close(fd);
238 	}
239 
240 	/* clear the cursor */
241 	fd = open("/dev/cursor", OWRITE);
242 	if(fd > 0){
243 		memset(cbuf, 0, sizeof cbuf);
244 		write(fd, cbuf, sizeof cbuf);
245 		/* leave it open */
246 	}
247 }
248 
249 void
250 threadmain(int argc, char *argv[])
251 {
252 	readfile("#c/user", user, sizeof user, 1);
253 
254 	if((vgactl = open("/dev/vgactl", OWRITE)) < 0)
255 		vgactl = open("#v/vgactl", OWRITE);
256 
257 	ARGBEGIN{
258 	case 'd':
259 		debug++;
260 		break;
261 	default:
262 		usage();
263 	}ARGEND
264 
265 	if(argc != 0)
266 		usage();
267 
268 	doblank = 1;
269 	lockscreen();
270 	checkpassword();
271 	threadexitsall(nil);
272 }
273