screenlock.c 5.3 KB

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