xref: /plan9/sys/src/cmd/screenlock.c (revision 047f1f95aa802225c557b6f2f4b096acb12ebb86)
150ee8570SDavid du Colombier /* screenlock - lock a terminal */
250ee8570SDavid du Colombier #include <u.h>
350ee8570SDavid du Colombier #include <libc.h>
450ee8570SDavid du Colombier #include <libsec.h>
550ee8570SDavid du Colombier #include <draw.h>
650ee8570SDavid du Colombier #include <thread.h>
750ee8570SDavid du Colombier #include <auth.h>
850ee8570SDavid du Colombier 
950ee8570SDavid du Colombier char pic[] = "/lib/bunny.bit";
1050ee8570SDavid du Colombier 
1150ee8570SDavid du Colombier int vgactl;
1250ee8570SDavid du Colombier int debug;
1350ee8570SDavid du Colombier int doblank;
1450ee8570SDavid du Colombier int chatty = 0;
1550ee8570SDavid du Colombier 
1650ee8570SDavid du Colombier char user[256];
1750ee8570SDavid du Colombier 
1850ee8570SDavid du Colombier void
blankscreen(int blank)1950ee8570SDavid du Colombier blankscreen(int blank)
2050ee8570SDavid du Colombier {
2150ee8570SDavid du Colombier 	if(vgactl < 0)
2250ee8570SDavid du Colombier 		return;
2350ee8570SDavid du Colombier 	seek(vgactl, 0, 0);
2450ee8570SDavid du Colombier 	if(fprint(vgactl, blank? "blank": "unblank") < 0)
2550ee8570SDavid du Colombier 		fprint(2, "blankscreen: can't blank: %r\n");
2650ee8570SDavid du Colombier }
2750ee8570SDavid du Colombier 
2850ee8570SDavid du Colombier void
error(char * fmt,...)2950ee8570SDavid du Colombier error(char *fmt, ...)
3050ee8570SDavid du Colombier {
3150ee8570SDavid du Colombier 	Fmt f;
3250ee8570SDavid du Colombier 	char buf[64];
3350ee8570SDavid du Colombier 	va_list arg;
3450ee8570SDavid du Colombier 
3550ee8570SDavid du Colombier 	fmtfdinit(&f, 1, buf, sizeof buf);
3650ee8570SDavid du Colombier 	fmtprint(&f, "screenlock: ");
3750ee8570SDavid du Colombier 	va_start(arg, fmt);
3850ee8570SDavid du Colombier 	fmtvprint(&f, fmt, arg);
3950ee8570SDavid du Colombier 	va_end(arg);
4050ee8570SDavid du Colombier 	fmtprint(&f, "\n");
4150ee8570SDavid du Colombier 	fmtfdflush(&f);
4250ee8570SDavid du Colombier 	threadexitsall("fatal error");
4350ee8570SDavid du Colombier }
4450ee8570SDavid du Colombier 
4550ee8570SDavid du Colombier void
usage(void)4650ee8570SDavid du Colombier usage(void)
4750ee8570SDavid du Colombier {
4850ee8570SDavid du Colombier 	fprint(2, "usage: %s\n", argv0);
4950ee8570SDavid du Colombier 	exits("usage");
5050ee8570SDavid du Colombier }
5150ee8570SDavid du Colombier 
5250ee8570SDavid du Colombier 
5350ee8570SDavid du Colombier void
readfile(char * name,char * buf,int nbuf,int addnul)5450ee8570SDavid du Colombier readfile(char *name, char *buf, int nbuf, int addnul)
5550ee8570SDavid du Colombier {
5650ee8570SDavid du Colombier 	int fd;
5750ee8570SDavid du Colombier 
5850ee8570SDavid du Colombier 	fd = open(name, OREAD);
5950ee8570SDavid du Colombier 	if(fd == -1)
6050ee8570SDavid du Colombier 		error("%s - can't open: %r", name);
6150ee8570SDavid du Colombier 	nbuf = read(fd, buf, nbuf-addnul);
6250ee8570SDavid du Colombier 	close(fd);
6350ee8570SDavid du Colombier 	if(nbuf == -1)
6450ee8570SDavid du Colombier 		error("%s - can't can't read: %r", name);
6550ee8570SDavid du Colombier 	if(addnul)
6650ee8570SDavid du Colombier 		buf[nbuf] = '\0';
6750ee8570SDavid du Colombier }
6850ee8570SDavid du Colombier 
6950ee8570SDavid du Colombier void
readline(char * buf,int nbuf)7050ee8570SDavid du Colombier readline(char *buf, int nbuf)
7150ee8570SDavid du Colombier {
7250ee8570SDavid du Colombier 	char c;
7350ee8570SDavid du Colombier 	int i;
7450ee8570SDavid du Colombier 
7550ee8570SDavid du Colombier 	i = 0;
7650ee8570SDavid du Colombier 	while(i < nbuf-1)
7750ee8570SDavid du Colombier 		if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){
7850ee8570SDavid du Colombier 			i = 0;
7950ee8570SDavid du Colombier 			break;
8050ee8570SDavid du Colombier 		} else if(c == '\n')
8150ee8570SDavid du Colombier 			break;
8250ee8570SDavid du Colombier 		else if(c == '\b' && i > 0)
8350ee8570SDavid du Colombier 			--i;
8450ee8570SDavid du Colombier 		else if(c == ('u' & 037))
8550ee8570SDavid du Colombier 			i = 0;
8650ee8570SDavid du Colombier 		else
8750ee8570SDavid du Colombier 			buf[i++] = c;
8850ee8570SDavid du Colombier 	buf[i] = '\0';
8950ee8570SDavid du Colombier }
9050ee8570SDavid du Colombier 
9150ee8570SDavid du Colombier void
checkpassword(void)9250ee8570SDavid du Colombier checkpassword(void)
9350ee8570SDavid du Colombier {
9450ee8570SDavid du Colombier 	int fd, consctl, must;
9550ee8570SDavid du Colombier 	char buf[256];
9650ee8570SDavid du Colombier 	AuthInfo *ai;
9750ee8570SDavid du Colombier 	static int opened;
9850ee8570SDavid du Colombier 
9950ee8570SDavid du Colombier 	must = 1;
10050ee8570SDavid du Colombier 	if(!opened){
10150ee8570SDavid du Colombier 		fd = open("/dev/cons", OREAD);
10250ee8570SDavid du Colombier 		if(fd == -1)
10350ee8570SDavid du Colombier 			error("can't open cons: %r");
10450ee8570SDavid du Colombier 		dup(fd, 0);
10550ee8570SDavid du Colombier 		close(fd);
10650ee8570SDavid du Colombier 		fd = open("/dev/cons", OWRITE);
10750ee8570SDavid du Colombier 		if(fd == -1)
10850ee8570SDavid du Colombier 			error("can't open cons: %r");
10950ee8570SDavid du Colombier 		dup(fd, 1);
11050ee8570SDavid du Colombier 		dup(1, 2);
11150ee8570SDavid du Colombier 		close(fd);
11250ee8570SDavid du Colombier 		consctl = open("/dev/consctl", OWRITE);
11350ee8570SDavid du Colombier 		if(consctl == -1)
11450ee8570SDavid du Colombier 			error("can't open consctl: %r");
11550ee8570SDavid du Colombier 		if(write(consctl, "rawon", 5) != 5)
11650ee8570SDavid du Colombier 			error("can't turn off echo\n");
11750ee8570SDavid du Colombier 		opened = 1;
11850ee8570SDavid du Colombier 	}
11950ee8570SDavid du Colombier 
12050ee8570SDavid du Colombier 	for(;;){
12150ee8570SDavid du Colombier 		if(chatty || !must)
12250ee8570SDavid du Colombier 			fprint(2, "%s's screenlock password: ", user);
12350ee8570SDavid du Colombier 		memset(buf, 0, sizeof buf);
12450ee8570SDavid du Colombier 		readline(buf, sizeof buf);
12550ee8570SDavid du Colombier 		blankscreen(0);
12650ee8570SDavid du Colombier 		if(chatty || !must)
12750ee8570SDavid du Colombier 			fprint(2, "\n");
12850ee8570SDavid du Colombier 		if(buf[0] == '\0' || buf[0] == '\04'){
12950ee8570SDavid du Colombier 			if(must)
13050ee8570SDavid du Colombier 				continue;
13150ee8570SDavid du Colombier 			error("no password typed");
13250ee8570SDavid du Colombier 		}
13350ee8570SDavid du Colombier 
13450ee8570SDavid du Colombier 		/* authenticate */
13550ee8570SDavid du Colombier 		ai = auth_userpasswd(user, buf);
13650ee8570SDavid du Colombier 		if(ai != nil && ai->cap != nil)
13750ee8570SDavid du Colombier 			break;
13850ee8570SDavid du Colombier 		auth_freeAI(ai);
13950ee8570SDavid du Colombier 
14050ee8570SDavid du Colombier 		if(chatty || !must)
14150ee8570SDavid du Colombier 			fprint(2, "password mismatch\n");
14250ee8570SDavid du Colombier 		doblank = 1;
14350ee8570SDavid du Colombier 	}
14450ee8570SDavid du Colombier 	memset(buf, 0, sizeof buf);
14550ee8570SDavid du Colombier 	blankscreen(0);
14650ee8570SDavid du Colombier }
14750ee8570SDavid du Colombier 
14850ee8570SDavid du Colombier void
blanker(void *)14950ee8570SDavid du Colombier blanker(void *)
15050ee8570SDavid du Colombier {
15150ee8570SDavid du Colombier 	int tics;
15250ee8570SDavid du Colombier 
15350ee8570SDavid du Colombier 	tics = 0;
15450ee8570SDavid du Colombier 	for(;;){
15550ee8570SDavid du Colombier 		if(doblank > 0){
15650ee8570SDavid du Colombier 			doblank = 0;
15750ee8570SDavid du Colombier 			tics = 10;
15850ee8570SDavid du Colombier 		}
15950ee8570SDavid du Colombier 		if(tics > 0 && --tics == 0)
16050ee8570SDavid du Colombier 			blankscreen(1);
16150ee8570SDavid du Colombier 		sleep(1000);
16250ee8570SDavid du Colombier 	}
16350ee8570SDavid du Colombier }
16450ee8570SDavid du Colombier 
16550ee8570SDavid du Colombier void
grabmouse(void *)16650ee8570SDavid du Colombier grabmouse(void*)
16750ee8570SDavid du Colombier {
16850ee8570SDavid du Colombier 	int fd, x, y;
16950ee8570SDavid du Colombier 	char ibuf[256], obuf[256];
17050ee8570SDavid du Colombier 
17150ee8570SDavid du Colombier 	if(debug)
17250ee8570SDavid du Colombier 		return;
17350ee8570SDavid du Colombier 	fd = open("/dev/mouse", ORDWR);
17450ee8570SDavid du Colombier 	if(fd < 0)
17550ee8570SDavid du Colombier 		error("can't open /dev/mouse: %r");
17650ee8570SDavid du Colombier 
17750ee8570SDavid du Colombier 	snprint(obuf, sizeof obuf, "m %d %d",
17850ee8570SDavid du Colombier 		screen->r.min.x + Dx(screen->r)/2,
17950ee8570SDavid du Colombier 		screen->r.min.y + Dy(screen->r)/2);
18050ee8570SDavid du Colombier 	while(read(fd, ibuf, sizeof ibuf) > 0){
18150ee8570SDavid du Colombier 		ibuf[12] = 0;
18250ee8570SDavid du Colombier 		ibuf[24] = 0;
18350ee8570SDavid du Colombier 		x = atoi(ibuf+1);
18450ee8570SDavid du Colombier 		y = atoi(ibuf+13);
18550ee8570SDavid du Colombier 		if(x != screen->r.min.x + Dx(screen->r)/2 ||
18650ee8570SDavid du Colombier 		   y != screen->r.min.y + Dy(screen->r)/2){
18750ee8570SDavid du Colombier 			fprint(fd, "%s", obuf);
18850ee8570SDavid du Colombier 			doblank = 1;
18950ee8570SDavid du Colombier 		}
19050ee8570SDavid du Colombier 	}
19150ee8570SDavid du Colombier }
19250ee8570SDavid du Colombier 
1933468a491SDavid du Colombier /* lay down text at `p' */
1943468a491SDavid du Colombier static void
screenstring(Point p,char * s)1953468a491SDavid du Colombier screenstring(Point p, char *s)
1963468a491SDavid du Colombier {
1973468a491SDavid du Colombier 	string(screen, p, screen->display->white, ZP, font, s);
1983468a491SDavid du Colombier 	flushimage(display, 1);
1993468a491SDavid du Colombier }
2003468a491SDavid du Colombier 
20150ee8570SDavid du Colombier void
lockscreen(void)20250ee8570SDavid du Colombier lockscreen(void)
20350ee8570SDavid du Colombier {
20450ee8570SDavid du Colombier 	enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, };
2053468a491SDavid du Colombier 	char *s;
20650ee8570SDavid du Colombier 	char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen];
20750ee8570SDavid du Colombier 	int fd, dx, dy;
20850ee8570SDavid du Colombier 	Image *i;
2093468a491SDavid du Colombier 	Point p;
21050ee8570SDavid du Colombier 	Rectangle r;
2113468a491SDavid du Colombier 	Tm *tm;
21250ee8570SDavid du Colombier 
21350ee8570SDavid du Colombier 	fd = open("/dev/screen", OREAD);
21450ee8570SDavid du Colombier 	if(fd < 0)
21550ee8570SDavid du Colombier 		error("can't open /dev/screen: %r");
21650ee8570SDavid du Colombier 	if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen)
21750ee8570SDavid du Colombier 		error("can't read /dev/screen: %r");
21850ee8570SDavid du Colombier 	close(fd);
21950ee8570SDavid du Colombier 	buf[sizeof buf-1] = 0;
22050ee8570SDavid du Colombier 	if(tokenize(buf, flds, Nfld) != Nfld)
22150ee8570SDavid du Colombier 		error("can't tokenize /dev/screen header");
22250ee8570SDavid du Colombier 	snprint(newcmd, sizeof newcmd, "-r %s %s %d %d",
22350ee8570SDavid du Colombier 		flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1);
22450ee8570SDavid du Colombier 	newwindow(newcmd);
2253468a491SDavid du Colombier 	if (initdraw(nil, nil, "screenlock") < 0)
2263468a491SDavid du Colombier 		sysfatal("initdraw failed");
22750ee8570SDavid du Colombier 	if(display == nil)
22850ee8570SDavid du Colombier 		error("no display");
22950ee8570SDavid du Colombier 
23050ee8570SDavid du Colombier 	/* screen is now open and covered.  grab mouse and hold on tight */
23150ee8570SDavid du Colombier 	procrfork(grabmouse, nil, 4096, RFFDG);
23250ee8570SDavid du Colombier 	procrfork(blanker, nil, 4096, RFFDG);
23350ee8570SDavid du Colombier 	fd = open(pic, OREAD);
23450ee8570SDavid du Colombier 	if(fd > 0){
23550ee8570SDavid du Colombier 		i = readimage(display, fd, 0);
23650ee8570SDavid du Colombier 		if(i){
23750ee8570SDavid du Colombier  			r = screen->r;
2383468a491SDavid du Colombier 			p = Pt(r.max.x / 2, r.max.y * 2 / 3);
23950ee8570SDavid du Colombier 			dx = (Dx(screen->r) - Dx(i->r)) / 2;
24050ee8570SDavid du Colombier 			r.min.x += dx;
24150ee8570SDavid du Colombier 			r.max.x -= dx;
24250ee8570SDavid du Colombier 			dy = (Dy(screen->r) - Dy(i->r)) / 2;
24350ee8570SDavid du Colombier 			r.min.y += dy;
24450ee8570SDavid du Colombier 			r.max.y -= dy;
24550ee8570SDavid du Colombier 			draw(screen, screen->r, display->black, nil, ZP);
24650ee8570SDavid du Colombier 			draw(screen, r, i, nil, i->r.min);
24750ee8570SDavid du Colombier 			flushimage(display, 1);
24850ee8570SDavid du Colombier 		}
24950ee8570SDavid du Colombier 		close(fd);
2503468a491SDavid du Colombier 
2513468a491SDavid du Colombier 		/* identify the user on screen, centered */
2523468a491SDavid du Colombier 		tm = localtime(time(0));
253*047f1f95SDavid du Colombier 		s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min);
2542ce711d4SDavid du Colombier 		p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0));
2553468a491SDavid du Colombier 		screenstring(p, s);
25650ee8570SDavid du Colombier 	}
25750ee8570SDavid du Colombier 
25850ee8570SDavid du Colombier 	/* clear the cursor */
25950ee8570SDavid du Colombier 	fd = open("/dev/cursor", OWRITE);
26050ee8570SDavid du Colombier 	if(fd > 0){
26150ee8570SDavid du Colombier 		memset(cbuf, 0, sizeof cbuf);
26250ee8570SDavid du Colombier 		write(fd, cbuf, sizeof cbuf);
26350ee8570SDavid du Colombier 		/* leave it open */
26450ee8570SDavid du Colombier 	}
26550ee8570SDavid du Colombier }
26650ee8570SDavid du Colombier 
26750ee8570SDavid du Colombier void
threadmain(int argc,char * argv[])26850ee8570SDavid du Colombier threadmain(int argc, char *argv[])
26950ee8570SDavid du Colombier {
27050ee8570SDavid du Colombier 	readfile("#c/user", user, sizeof user, 1);
27150ee8570SDavid du Colombier 
27250ee8570SDavid du Colombier 	if((vgactl = open("/dev/vgactl", OWRITE)) < 0)
27350ee8570SDavid du Colombier 		vgactl = open("#v/vgactl", OWRITE);
27450ee8570SDavid du Colombier 
27550ee8570SDavid du Colombier 	ARGBEGIN{
27650ee8570SDavid du Colombier 	case 'd':
27750ee8570SDavid du Colombier 		debug++;
27850ee8570SDavid du Colombier 		break;
27950ee8570SDavid du Colombier 	default:
28050ee8570SDavid du Colombier 		usage();
28150ee8570SDavid du Colombier 	}ARGEND
28250ee8570SDavid du Colombier 
28350ee8570SDavid du Colombier 	if(argc != 0)
28450ee8570SDavid du Colombier 		usage();
28550ee8570SDavid du Colombier 
28650ee8570SDavid du Colombier 	doblank = 1;
28750ee8570SDavid du Colombier 	lockscreen();
28850ee8570SDavid du Colombier 	checkpassword();
28950ee8570SDavid du Colombier 	threadexitsall(nil);
29050ee8570SDavid du Colombier }
291