Rob Pike contributed these ages ago. -Steve Notes: Tue Feb 22 08:46:56 EST 2005 jmk Tue Feb 22 08:48:50 EST 2005 jmk sape worked on lock to make it more useable. i will send you a copy so you can write the man page for that (screenlock) and delkey. --jim Reference: /n/sources/patch/sorry/robs-bits Date: Tue Feb 22 11:03:47 CET 2005 Reviewed-by: rsc --- /rc/bin/delkey Thu Jan 1 00:00:00 1970 +++ /rc/bin/delkey Tue Feb 22 11:02:00 2005 @@ -0,0 +1,52 @@ +#!/bin/rc + +rfork e + +ctl = /mnt/factotum/ctl +if(test -r /mnt/term/mnt/factotum/ctl) + ctl = /mnt/term/mnt/factotum/ctl + +fn forceit { + switch($force){ + case no + echo -n $* '? [y/n]' > /dev/cons + ok = `{read} + switch($ok){ + case y* Y* + echo yes + case q* Q* + exit '' + case * + echo no + } + case * + echo yes + } +} + +fn deleteit { + key = `{echo $* | sed 's/ ![0-9a-zA-Z_]+\??/ /g' | sed 's/ +$//'} + if(~ `{forceit del$key} yes) + if(! echo del$key > $ctl) + exit bad +} + +force = no + +if(~ $1 '-f'){ + force = yes + shift +} + +ifs=' +' + +if(~ $#* 0){ + for(i in `{cat $ctl}) + deleteit $i + exit '' +} + +for(i in `{grep $"* $ctl}) + deleteit $i +exit '' --- /sys/src/cmd/lock.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/lock.c Tue Feb 22 11:02:11 2005 @@ -0,0 +1,294 @@ +#include +#include +#include +#include + +char pic[] = "/lib/bunny.bit"; + +int vgactl; +int debug; + +uchar storedhash[SHA1dlen]; +uchar thishash[SHA1dlen]; +char user[256]; +char home[256]; +char hashfile[256]; + +void +error(char *fmt, ...) +{ + Fmt f; + char buf[64]; + va_list arg; + + fmtfdinit(&f, 1, buf, sizeof buf); + fmtprint(&f, "lock: "); + va_start(arg, fmt); + fmtvprint(&f, fmt, arg); + va_end(arg); + fmtprint(&f, "\n"); + fmtfdflush(&f); + postnote(PNGROUP, getpid(), "die"); + exits("fatal error"); +} + +void +usage(void) +{ + fprint(2, "usage: lock [-p]\n"); + 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'; +} + +int +readstoredhash(int mustexist) +{ + if(access(hashfile, AEXIST) < 0){ + if(!mustexist) + return 0; + error("no password set; use lock -p to set password"); + } + readfile(hashfile, (char*)storedhash, sizeof storedhash, 0); + return 1; +} + +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'){ + buf[0] = '\0'; + return; + } + if(c == '\n'){ + buf[i] = '\0'; + return; + } + if(c == '\b' && i > 0){ + --i; + continue; + } + if(c == '\025'){ + i = 0; + continue; + } + buf[i++] = c; + } +} + +void +checkpassword(int must) +{ + char buf[256]; + static int opened; + int fd, consctl; + + 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(;;){ + fprint(2, "password: "); + readline(buf, sizeof buf); + fprint(2, "\n"); + if(buf[0] == '\0' || buf[0] == '\04'){ + if(must) + continue; + error("no password typed"); + } + sha1((uchar*)buf, strlen(buf), thishash, nil); + memset(buf, 0, sizeof buf); + if(memcmp(thishash, storedhash, sizeof storedhash) == 0) + break; + fprint(2, "password mismatch\n"); + } +} + +void +changepassword(void) +{ + int fd; + char buf[256]; + + if(readstoredhash(0)) + checkpassword(0); + for(;;){ + fprint(2, "password: "); + readline(buf, sizeof buf); + fprint(2, "\n"); + if(buf[0] == '\0' || buf[0] == '\04') + exits("no password typed"); + sha1((uchar*)buf, strlen(buf), thishash, nil); + memset(buf, 0, sizeof buf); + fprint(2, "re-type password: "); + readline(buf, sizeof buf); + fprint(2, "\n"); + if(buf[0] == '\0' || buf[0] == '\04') + exits("no password typed"); + sha1((uchar*)buf, strlen(buf), storedhash, nil); + memset(buf, 0, sizeof buf); + if(memcmp(storedhash, thishash, sizeof storedhash) != 0){ + fprint(2, "password mismatch\n"); + continue; + } + + fd = create(hashfile, OWRITE, 0600); + if(fd < 0) + error("can't create hashfile: %r"); + if(write(fd, storedhash, sizeof storedhash) != sizeof storedhash) + error("error writing hashfile: %r"); + break; + } +} + +void +grabmouse(void) +{ + int fd; + char ibuf[256], obuf[256]; + + if(debug) + return; + fd = open("/dev/mouse", ORDWR); + if(fd < 0) + error("can't open /dev/mouse: %r"); + switch(fork()){ + case -1: + error("can't fork mouse process: %r"); + default: + return; + case 0: + break; + } + + 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) + fprint(fd, "%s", obuf); +} + +void +lockscreen(void) +{ + enum { Nfld=5, Fldlen = 12 }; + char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128]; + enum { Cursorlen=2*4+2*2*16 }; + char cbuf[Cursorlen]; + int fd, dx, dy; + Image *i; + Rectangle r; + + fd = open("/dev/screen", OREAD); + if(fd < 0) + error("can't open /dev/screen: %r"); + 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); + initdraw(nil, nil, "lock"); + + /* screen is now open and covered. grab mouse and hold on tight */ + grabmouse(); + fd = open(pic, OREAD); + if(fd > 0){ + i = readimage(display, fd, 0); + if(i){ + r = screen->r; + 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, r, i, nil, i->r.min); + flushimage(display, 1); + } + close(fd); + } + + /* clear the cursor */ + fd = open("/dev/cursor", OWRITE); + if(fd > 0){ + memset(cbuf, 0, sizeof cbuf); + write(fd, cbuf, sizeof cbuf); + /* leave it open */ + } + + fprint(vgactl, "blank"); +} + +void +main(int argc, char *argv[]) +{ + readfile("#c/user", user, sizeof user, 1); + readfile("#e/home", home, sizeof home, 1); + snprint(hashfile, sizeof hashfile, "%s/lib/lockhash", home); + + vgactl = open("#v/vgactl", OWRITE); + if(vgactl == -1) + error("can't open vgactl: %r"); + + ARGBEGIN{ + case 'd': + debug++; + break; + case 'p': + changepassword(); + exits(nil); + default: + usage(); + }ARGEND + + if(argc != 0) + usage(); + + readstoredhash(1); + rfork(RFNOTEG); + lockscreen(); + checkpassword(1); + postnote(PNGROUP, getpid(), "die"); + exits(nil); +}