/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* screenlock - lock a terminal */ #include #include #include #include #include #include #include char pic[] = "/lib/bunny.bit"; int vgactl; int debug; int doblank; int chatty = 0; char user[256]; void blankscreen(int blank) { if(vgactl < 0) return; seek(vgactl, 0, 0); if(fprint(vgactl, blank? "blank": "unblank") < 0) fprint(2, "blankscreen: can't blank: %r\n"); } void error(char *fmt, ...) { Fmt f; char buf[64]; va_list arg; fmtfdinit(&f, 1, buf, sizeof buf); fmtprint(&f, "screenlock: "); va_start(arg, fmt); fmtvprint(&f, fmt, arg); va_end(arg); fmtprint(&f, "\n"); fmtfdflush(&f); threadexitsall("fatal error"); } void usage(void) { fprint(2, "usage: %s\n", argv0); exits("usage"); } void readfile(char *name, char *buf, int nbuf, int addnul) { int fd; fd = open(name, OREAD); if(fd == -1) error("%s - can't open: %r", name); nbuf = read(fd, buf, nbuf-addnul); close(fd); if(nbuf == -1) error("%s - can't can't read: %r", name); if(addnul) buf[nbuf] = '\0'; } void readline(char *buf, int nbuf) { char c; int i; i = 0; while(i < nbuf-1) if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){ i = 0; break; } else if(c == '\n') break; else if(c == '\b' && i > 0) --i; else if(c == ('u' & 037)) i = 0; else buf[i++] = c; buf[i] = '\0'; } void checkpassword(void) { int fd, consctl, must; char buf[256]; AuthInfo *ai; static int opened; must = 1; if(!opened){ fd = open("/dev/cons", OREAD); if(fd == -1) error("can't open cons: %r"); dup(fd, 0); close(fd); fd = open("/dev/cons", OWRITE); if(fd == -1) error("can't open cons: %r"); dup(fd, 1); dup(1, 2); close(fd); consctl = open("/dev/consctl", OWRITE); if(consctl == -1) error("can't open consctl: %r"); if(write(consctl, "rawon", 5) != 5) error("can't turn off echo\n"); opened = 1; } for(;;){ if(chatty || !must) fprint(2, "%s's screenlock password: ", user); memset(buf, 0, sizeof buf); readline(buf, sizeof buf); blankscreen(0); if(chatty || !must) fprint(2, "\n"); if(buf[0] == '\0' || buf[0] == '\04'){ if(must) continue; error("no password typed"); } /* authenticate */ ai = auth_userpasswd(user, buf); if(ai != nil && ai->cap != nil) break; auth_freeAI(ai); if(chatty || !must) fprint(2, "password mismatch\n"); doblank = 1; } memset(buf, 0, sizeof buf); blankscreen(0); } void blanker(void *v) { int tics; tics = 0; for(;;){ if(doblank > 0){ doblank = 0; tics = 10; } if(tics > 0 && --tics == 0) blankscreen(1); sleep(1000); } } void grabmouse(void *v) { int fd, x, y; char ibuf[256], obuf[256]; if(debug) return; fd = open("/dev/mouse", ORDWR); if(fd < 0) error("can't open /dev/mouse: %r"); snprint(obuf, sizeof obuf, "m %d %d", screen->r.min.x + Dx(screen->r)/2, screen->r.min.y + Dy(screen->r)/2); while(read(fd, ibuf, sizeof ibuf) > 0){ ibuf[12] = 0; ibuf[24] = 0; x = atoi(ibuf+1); y = atoi(ibuf+13); if(x != screen->r.min.x + Dx(screen->r)/2 || y != screen->r.min.y + Dy(screen->r)/2){ fprint(fd, "%s", obuf); doblank = 1; } } } /* lay down text at `p' */ static void screenstring(Point p, char *s) { string(screen, p, screen->display->white, ZP, font, s); flushimage(display, 1); } void lockscreen(void) { enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, }; int fd = open("/dev/screen", OREAD); if(fd < 0) error("can't open /dev/screen: %r"); char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128]; if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen) error("can't read /dev/screen: %r"); close(fd); buf[sizeof buf-1] = 0; if(tokenize(buf, flds, Nfld) != Nfld) error("can't tokenize /dev/screen header"); snprint(newcmd, sizeof newcmd, "-r %s %s %d %d", flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1); newwindow(newcmd); if(initdraw(nil, nil, "screenlock") < 0) sysfatal("initdraw failed"); if(display == nil) error("no display"); /* screen is now open and covered. grab mouse and hold on tight */ procrfork(grabmouse, nil, 4096, RFFDG); procrfork(blanker, nil, 4096, RFFDG); Rectangle r = screen->r; draw(screen, r, display->black, nil, ZP); // Try to load and display an image in the centre of the screen fd = open(pic, OREAD); if(fd > 0){ Image *i = readimage(display, fd, 0); close(fd); if(i){ int dx = (Dx(screen->r) - Dx(i->r)) / 2; r.min.x += dx; r.max.x -= dx; int dy = (Dy(screen->r) - Dy(i->r)) / 2; r.min.y += dy; r.max.y -= dy; draw(screen, r, i, nil, i->r.min); flushimage(display, 1); } } /* identify the user on screen, centered */ Tm *tm = localtime(time(0)); char *s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min); Point p = Pt(r.max.x / 2, r.max.y * 2 / 3); p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0)); screenstring(p, s); /* clear the cursor */ fd = open("/dev/cursor", OWRITE); if(fd > 0){ char cbuf[Cursorlen]; memset(cbuf, 0, sizeof cbuf); write(fd, cbuf, sizeof cbuf); /* leave it open */ } } void threadmain(int argc, char *argv[]) { readfile("#c/user", user, sizeof user, 1); if((vgactl = open("/dev/vgactl", OWRITE)) < 0) vgactl = open("#v/vgactl", OWRITE); ARGBEGIN{ case 'd': debug++; break; default: usage(); }ARGEND if(argc != 0) usage(); doblank = 1; lockscreen(); checkpassword(); threadexitsall(nil); }