1 /* screenlock - lock a terminal */ 2 #include <u.h> 3 #include <libc.h> 4 #include <libsec.h> 5 #include <draw.h> 6 #include <thread.h> 7 #include <auth.h> 8 9 char pic[] = "/lib/bunny.bit"; 10 11 int vgactl; 12 int debug; 13 int doblank; 14 int chatty = 0; 15 16 char user[256]; 17 18 void 19 blankscreen(int blank) 20 { 21 if(vgactl < 0) 22 return; 23 seek(vgactl, 0, 0); 24 if(fprint(vgactl, blank? "blank": "unblank") < 0) 25 fprint(2, "blankscreen: can't blank: %r\n"); 26 } 27 28 void 29 error(char *fmt, ...) 30 { 31 Fmt f; 32 char buf[64]; 33 va_list arg; 34 35 fmtfdinit(&f, 1, buf, sizeof buf); 36 fmtprint(&f, "screenlock: "); 37 va_start(arg, fmt); 38 fmtvprint(&f, fmt, arg); 39 va_end(arg); 40 fmtprint(&f, "\n"); 41 fmtfdflush(&f); 42 threadexitsall("fatal error"); 43 } 44 45 void 46 usage(void) 47 { 48 fprint(2, "usage: %s\n", argv0); 49 exits("usage"); 50 } 51 52 53 void 54 readfile(char *name, char *buf, int nbuf, int addnul) 55 { 56 int fd; 57 58 fd = open(name, OREAD); 59 if(fd == -1) 60 error("%s - can't open: %r", name); 61 nbuf = read(fd, buf, nbuf-addnul); 62 close(fd); 63 if(nbuf == -1) 64 error("%s - can't can't read: %r", name); 65 if(addnul) 66 buf[nbuf] = '\0'; 67 } 68 69 void 70 readline(char *buf, int nbuf) 71 { 72 char c; 73 int i; 74 75 i = 0; 76 while(i < nbuf-1) 77 if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){ 78 i = 0; 79 break; 80 } else if(c == '\n') 81 break; 82 else if(c == '\b' && i > 0) 83 --i; 84 else if(c == ('u' & 037)) 85 i = 0; 86 else 87 buf[i++] = c; 88 buf[i] = '\0'; 89 } 90 91 void 92 checkpassword(void) 93 { 94 int fd, consctl, must; 95 char buf[256]; 96 AuthInfo *ai; 97 static int opened; 98 99 must = 1; 100 if(!opened){ 101 fd = open("/dev/cons", OREAD); 102 if(fd == -1) 103 error("can't open cons: %r"); 104 dup(fd, 0); 105 close(fd); 106 fd = open("/dev/cons", OWRITE); 107 if(fd == -1) 108 error("can't open cons: %r"); 109 dup(fd, 1); 110 dup(1, 2); 111 close(fd); 112 consctl = open("/dev/consctl", OWRITE); 113 if(consctl == -1) 114 error("can't open consctl: %r"); 115 if(write(consctl, "rawon", 5) != 5) 116 error("can't turn off echo\n"); 117 opened = 1; 118 } 119 120 for(;;){ 121 if(chatty || !must) 122 fprint(2, "%s's screenlock password: ", user); 123 memset(buf, 0, sizeof buf); 124 readline(buf, sizeof buf); 125 blankscreen(0); 126 if(chatty || !must) 127 fprint(2, "\n"); 128 if(buf[0] == '\0' || buf[0] == '\04'){ 129 if(must) 130 continue; 131 error("no password typed"); 132 } 133 134 /* authenticate */ 135 ai = auth_userpasswd(user, buf); 136 if(ai != nil && ai->cap != nil) 137 break; 138 auth_freeAI(ai); 139 140 if(chatty || !must) 141 fprint(2, "password mismatch\n"); 142 doblank = 1; 143 } 144 memset(buf, 0, sizeof buf); 145 blankscreen(0); 146 } 147 148 void 149 blanker(void *) 150 { 151 int tics; 152 153 tics = 0; 154 for(;;){ 155 if(doblank > 0){ 156 doblank = 0; 157 tics = 10; 158 } 159 if(tics > 0 && --tics == 0) 160 blankscreen(1); 161 sleep(1000); 162 } 163 } 164 165 void 166 grabmouse(void*) 167 { 168 int fd, x, y; 169 char ibuf[256], obuf[256]; 170 171 if(debug) 172 return; 173 fd = open("/dev/mouse", ORDWR); 174 if(fd < 0) 175 error("can't open /dev/mouse: %r"); 176 177 snprint(obuf, sizeof obuf, "m %d %d", 178 screen->r.min.x + Dx(screen->r)/2, 179 screen->r.min.y + Dy(screen->r)/2); 180 while(read(fd, ibuf, sizeof ibuf) > 0){ 181 ibuf[12] = 0; 182 ibuf[24] = 0; 183 x = atoi(ibuf+1); 184 y = atoi(ibuf+13); 185 if(x != screen->r.min.x + Dx(screen->r)/2 || 186 y != screen->r.min.y + Dy(screen->r)/2){ 187 fprint(fd, "%s", obuf); 188 doblank = 1; 189 } 190 } 191 } 192 193 /* lay down text at `p' */ 194 static void 195 screenstring(Point p, char *s) 196 { 197 string(screen, p, screen->display->white, ZP, font, s); 198 flushimage(display, 1); 199 } 200 201 void 202 lockscreen(void) 203 { 204 enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, }; 205 char *s; 206 char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen]; 207 int fd, dx, dy; 208 Image *i; 209 Point p; 210 Rectangle r; 211 Tm *tm; 212 213 fd = open("/dev/screen", OREAD); 214 if(fd < 0) 215 error("can't open /dev/screen: %r"); 216 if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen) 217 error("can't read /dev/screen: %r"); 218 close(fd); 219 buf[sizeof buf-1] = 0; 220 if(tokenize(buf, flds, Nfld) != Nfld) 221 error("can't tokenize /dev/screen header"); 222 snprint(newcmd, sizeof newcmd, "-r %s %s %d %d", 223 flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1); 224 newwindow(newcmd); 225 if (initdraw(nil, nil, "screenlock") < 0) 226 sysfatal("initdraw failed"); 227 if(display == nil) 228 error("no display"); 229 230 /* screen is now open and covered. grab mouse and hold on tight */ 231 procrfork(grabmouse, nil, 4096, RFFDG); 232 procrfork(blanker, nil, 4096, RFFDG); 233 fd = open(pic, OREAD); 234 if(fd > 0){ 235 i = readimage(display, fd, 0); 236 if(i){ 237 r = screen->r; 238 p = Pt(r.max.x / 2, r.max.y * 2 / 3); 239 dx = (Dx(screen->r) - Dx(i->r)) / 2; 240 r.min.x += dx; 241 r.max.x -= dx; 242 dy = (Dy(screen->r) - Dy(i->r)) / 2; 243 r.min.y += dy; 244 r.max.y -= dy; 245 draw(screen, screen->r, display->black, nil, ZP); 246 draw(screen, r, i, nil, i->r.min); 247 flushimage(display, 1); 248 } 249 close(fd); 250 251 /* identify the user on screen, centered */ 252 tm = localtime(time(0)); 253 s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min); 254 p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0)); 255 screenstring(p, s); 256 } 257 258 /* clear the cursor */ 259 fd = open("/dev/cursor", OWRITE); 260 if(fd > 0){ 261 memset(cbuf, 0, sizeof cbuf); 262 write(fd, cbuf, sizeof cbuf); 263 /* leave it open */ 264 } 265 } 266 267 void 268 threadmain(int argc, char *argv[]) 269 { 270 readfile("#c/user", user, sizeof user, 1); 271 272 if((vgactl = open("/dev/vgactl", OWRITE)) < 0) 273 vgactl = open("#v/vgactl", OWRITE); 274 275 ARGBEGIN{ 276 case 'd': 277 debug++; 278 break; 279 default: 280 usage(); 281 }ARGEND 282 283 if(argc != 0) 284 usage(); 285 286 doblank = 1; 287 lockscreen(); 288 checkpassword(); 289 threadexitsall(nil); 290 } 291