/* screenlock - lock a terminal */ #include #include #include #include #include #include void redraw(void); void appendix(void); char pic[] = "/lib/bunny.bit"; char notice[28+14]; /* KNAMELEN + length of a string */ int debug; long blank; void usage(void) { fprint(2, "usage: %s [-d]\n", argv0); exits("usage"); } /* ^D, Delete, Enter, Backspace, ^U */ 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; blank = time(0); } buf[i] = '\0'; } void checkpassword(void) { char buf[256]; AuthInfo *ai; for(;;){ memset(buf, 0, sizeof buf); readline(buf, sizeof buf); border(screen, screen->r, 8, display->white, ZP); flushimage(display, 1); /* authenticate */ ai = auth_userpasswd(getuser(), buf); if(ai != nil && ai->cap != nil) break; rerrstr(buf, sizeof buf); if(strncmp(buf, "needkey ", 8) == 0) break; auth_freeAI(ai); border(screen, screen->r, 8, display->black, ZP); flushimage(display, 1); } auth_freeAI(ai); memset(buf, 0, sizeof buf); } void blanker(void *) { int fd; threadsetname("blanker"); if((fd = open("/dev/mousectl", OWRITE)) < 0) return; for(;;){ if(blank != 0 && ((ulong)time(0) - (ulong)blank) >= 5){ blank = 0; write(fd, "blank", 5); } sleep(1000); } } void grabmouse(void*) { int fd, x, y; char ibuf[256], obuf[256]; threadsetname("grabmouse"); if((fd = open("/dev/mouse", ORDWR)) < 0) sysfatal("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){ if(!debug) fprint(fd, "%s", obuf); blank = time(0); } } } void top(void*) { int fd, n; char buf[128]; threadsetname("top"); if((fd = open("/dev/wctl", ORDWR)) < 0) return; for(;;){ n = read(fd, buf, sizeof buf); if(n > 48) if(strstr(buf+48, "notcurrent")){ write(fd, "current", 7); /* rio redraws border… */ getwindow(display, 1); redraw(); } } } void redraw(void) { int fd, dx, dy; static Image *i; Point p, q; Rectangle r; screen = _screen->image; /* fullscreen */ if(i == nil){ fd = open(pic, OREAD); if(fd >= 0) i = readimage(display, fd, 0); close(fd); } if(i != nil){ fprint(2, "_screen"":%p\n", _screen); fprint(2, "_screen image"":%p\n", _screen->image); fprint(2, "_screen image r"":%p\n", &_screen->image->r); r = screen->r; p = Pt(r.max.x / 2, r.max.y * 2 / 3); dx = (Dx(screen->r) - Dx(i->r)) / 2; r.min.x += dx; r.max.x -= dx; dy = (Dy(screen->r) - Dy(i->r)) / 2; r.min.y += dy; r.max.y -= dy; draw(screen, screen->r, display->black, nil, ZP); draw(screen, r, i, nil, i->r.min); } /* identify the user on screen, centered */ q = stringsize(font, notice); q.x /= 2; p = subpt(p, q); stringbg( screen, p, display->white, ZP, font, notice, display->black, ZP ); flushimage(display, 1); } void lockscreen(void) { enum { Cursorlen = 2*4 + 2*2*16 }; char newcmd[128], cbuf[Cursorlen]; Rectangle r; int fd; Tm *tm; display = initdisplay(nil, nil, nil); if(display == nil) sysfatal("can't open /dev/draw: %r"); r = display->image->r; snprint(newcmd, sizeof newcmd, "-r %d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y); closedisplay(display); newwindow(newcmd); if((fd = open("/dev/consctl", OWRITE)) >= 0) write(fd, "rawon", 5); if((fd = open("/dev/cons", OREAD)) < 0) sysfatal("can't open cons: %r"); dup(fd, 0); if((fd = open("/dev/cons", OWRITE)) < 0) sysfatal("can't open cons: %r"); dup(fd, 1); dup(fd, 2); if(initdraw(nil, nil, "screenlock") < 0) sysfatal("initdraw failed"); tm = localtime(time(&blank)); sprint(notice, "user %s at %d:%02.2d", getuser(), tm->hour, tm->min); redraw(); /* screen is now open and covered. grab mouse and hold on tight */ procrfork(top, nil, 8*1024, RFFDG); procrfork(grabmouse, nil, 8*1024, RFFDG); procrfork(blanker, nil, 8*1024, RFFDG); /* clear the cursor */ if((fd = open("/dev/cursor", OWRITE)) >= 0){ memset(cbuf, 0, sizeof cbuf); write(fd, cbuf, sizeof cbuf); /* leave it open */ } /* do the top-getwindow-redraw cycle *here in the main proc* to show that it can actuall work */ // :232 and this call can't be uncommented at the same time - there // can be only one wctl reader //appendix(); } void threadmain(int argc, char *argv[]) { ARGBEGIN{ case 'd': debug++; break; default: usage(); }ARGEND if(argc != 0) usage(); lockscreen(); checkpassword(); threadexitsall(nil); } void appendix(void) { int fd;//, n; // char buf[128]; if((fd = open("/dev/wctl", ORDWR)) < 0) fprint(2, "%r"); sleep(1000); write(fd, "new echo", 8); sleep(1000); // if(strstr(buf+48, "notcurrent")){ write(fd, "current", 7); /* rio redraws border… */ getwindow(display, 1); redraw(); // } }