screenlock.c 5.7 KB

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