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 void 194 lockscreen(void) 195 { 196 enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, }; 197 char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen]; 198 int fd, dx, dy; 199 Image *i; 200 Rectangle r; 201 202 fd = open("/dev/screen", OREAD); 203 if(fd < 0) 204 error("can't open /dev/screen: %r"); 205 if(read(fd, buf, Nfld*Fldlen) != Nfld*Fldlen) 206 error("can't read /dev/screen: %r"); 207 close(fd); 208 buf[sizeof buf-1] = 0; 209 if(tokenize(buf, flds, Nfld) != Nfld) 210 error("can't tokenize /dev/screen header"); 211 snprint(newcmd, sizeof newcmd, "-r %s %s %d %d", 212 flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1); 213 newwindow(newcmd); 214 initdraw(nil, nil, "screenlock"); 215 216 if(display == nil) 217 error("no display"); 218 219 /* screen is now open and covered. grab mouse and hold on tight */ 220 procrfork(grabmouse, nil, 4096, RFFDG); 221 procrfork(blanker, nil, 4096, RFFDG); 222 fd = open(pic, OREAD); 223 if(fd > 0){ 224 i = readimage(display, fd, 0); 225 if(i){ 226 r = screen->r; 227 dx = (Dx(screen->r) - Dx(i->r)) / 2; 228 r.min.x += dx; 229 r.max.x -= dx; 230 dy = (Dy(screen->r) - Dy(i->r)) / 2; 231 r.min.y += dy; 232 r.max.y -= dy; 233 draw(screen, screen->r, display->black, nil, ZP); 234 draw(screen, r, i, nil, i->r.min); 235 flushimage(display, 1); 236 } 237 close(fd); 238 } 239 240 /* clear the cursor */ 241 fd = open("/dev/cursor", OWRITE); 242 if(fd > 0){ 243 memset(cbuf, 0, sizeof cbuf); 244 write(fd, cbuf, sizeof cbuf); 245 /* leave it open */ 246 } 247 } 248 249 void 250 threadmain(int argc, char *argv[]) 251 { 252 readfile("#c/user", user, sizeof user, 1); 253 254 if((vgactl = open("/dev/vgactl", OWRITE)) < 0) 255 vgactl = open("#v/vgactl", OWRITE); 256 257 ARGBEGIN{ 258 case 'd': 259 debug++; 260 break; 261 default: 262 usage(); 263 }ARGEND 264 265 if(argc != 0) 266 usage(); 267 268 doblank = 1; 269 lockscreen(); 270 checkpassword(); 271 threadexitsall(nil); 272 } 273