#include <u.h>
#include <libc.h>
#include <libsec.h>
#include <draw.h>
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);
}
|