]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/screenlock.c
9ac9fa06442b68315f1bc7e2e351f614019a7568
[plan9front.git] / sys / src / cmd / screenlock.c
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 int debug;
11 long blank;
12
13 void
14 usage(void)
15 {
16         fprint(2, "usage: %s [-d]\n", argv0);
17         exits("usage");
18 }
19
20 /* ^D, Delete, Enter, Backspace, ^U */
21 void
22 readline(char *buf, int nbuf)
23 {
24         char c;
25         int i;
26
27         i = 0;
28         while(i < nbuf-1){
29                 if(read(0, &c, 1) != 1 || c == '\04' || c == '\177'){
30                         i = 0;
31                         break;
32                 } else if(c == '\n')
33                         break;
34                 else if(c == '\b' && i > 0)
35                         --i;
36                 else if(c == ('u' & 037))
37                         i = 0;
38                 else
39                         buf[i++] = c;
40                 blank = time(0);
41         }
42         buf[i] = '\0';
43 }
44
45 void
46 checkpassword(void)
47 {
48         char buf[256];
49         AuthInfo *ai;
50
51         for(;;){
52                 memset(buf, 0, sizeof buf);
53                 readline(buf, sizeof buf);
54
55                 border(screen, screen->r, 8, display->white, ZP);
56                 flushimage(display, 1);
57
58                 /* authenticate */
59                 ai = auth_userpasswd(getuser(), buf);
60                 if(ai != nil && ai->cap != nil)
61                         break;
62
63                 rerrstr(buf, sizeof buf);
64                 if(strncmp(buf, "needkey ", 8) == 0)
65                         break;
66
67                 auth_freeAI(ai);
68                 border(screen, screen->r, 8, display->black, ZP);
69                 flushimage(display, 1);
70         }
71         auth_freeAI(ai);
72         memset(buf, 0, sizeof buf);
73 }
74
75 void
76 blanker(void *)
77 {
78         int fd;
79
80         if((fd = open("/dev/mousectl", OWRITE)) < 0)
81                 return;
82
83         for(;;){
84                 if(blank != 0 && ((ulong)time(0) - (ulong)blank) >= 5){
85                         blank = 0;
86                         write(fd, "blank", 5);
87                 }
88                 sleep(1000);
89         }
90 }
91
92 void
93 grabmouse(void*)
94 {
95         int fd, x, y;
96         char ibuf[256], obuf[256];
97
98         if((fd = open("/dev/mouse", ORDWR)) < 0)
99                 sysfatal("can't open /dev/mouse: %r");
100
101         snprint(obuf, sizeof obuf, "m %d %d",
102                 screen->r.min.x + Dx(screen->r)/2,
103                 screen->r.min.y + Dy(screen->r)/2);
104
105         while(read(fd, ibuf, sizeof ibuf) > 0){
106                 ibuf[12] = 0;
107                 ibuf[24] = 0;
108                 x = atoi(ibuf+1);
109                 y = atoi(ibuf+13);
110                 if(x != screen->r.min.x + Dx(screen->r)/2 ||
111                    y != screen->r.min.y + Dy(screen->r)/2){
112                         if(!debug)
113                                 fprint(fd, "%s", obuf);
114                         blank = time(0);
115                 }
116         }
117 }
118
119 void
120 top(void*)
121 {
122         int fd;
123
124         if((fd = open("/dev/wctl", OWRITE)) < 0)
125                 return;
126
127         for(;;){
128                 write(fd, "current", 7);
129                 sleep(500);
130         }
131 }
132
133 void
134 lockscreen(void)
135 {
136         enum { Cursorlen = 2*4 + 2*2*16 };
137         char *s;
138         char newcmd[128], cbuf[Cursorlen];
139         int fd, dx, dy;
140         Image *i;
141         Point p;
142         Rectangle r;
143         Tm *tm;
144
145         display = initdisplay(nil, nil, nil);
146         if(display == nil)
147                 sysfatal("can't open /dev/draw: %r");
148         r = display->image->r;
149         snprint(newcmd, sizeof newcmd, "-r %d %d %d %d",
150                 r.min.x, r.min.y, r.max.x, r.max.y);
151         closedisplay(display);
152
153         newwindow(newcmd);
154         if((fd = open("/dev/consctl", OWRITE)) >= 0)
155                 write(fd, "rawon", 5);
156
157         if((fd = open("/dev/cons", OREAD)) < 0)
158                 sysfatal("can't open cons: %r");
159         dup(fd, 0);
160
161         if((fd = open("/dev/cons", OWRITE)) < 0)
162                 sysfatal("can't open cons: %r");
163         dup(fd, 1);
164         dup(fd, 2);
165
166         if(initdraw(nil, nil, "screenlock") < 0)
167                 sysfatal("initdraw failed");
168         screen = _screen->image;        /* fullscreen */
169
170         if((fd = open(pic, OREAD)) >= 0){
171                 if((i = readimage(display, fd, 0)) != nil){
172                         r = screen->r;
173                         p = Pt(r.max.x / 2, r.max.y * 2 / 3); 
174                         dx = (Dx(screen->r) - Dx(i->r)) / 2;
175                         r.min.x += dx;
176                         r.max.x -= dx;
177                         dy = (Dy(screen->r) - Dy(i->r)) / 2;
178                         r.min.y += dy;
179                         r.max.y -= dy;
180                         draw(screen, screen->r, display->black, nil, ZP);
181                         draw(screen, r, i, nil, i->r.min);
182                 }
183                 close(fd);
184
185                 /* identify the user on screen, centered */
186                 tm = localtime(time(&blank));
187                 s = smprint("user %s at %d:%02.2d", getuser(), tm->hour, tm->min);
188                 p = subpt(p, Pt(stringwidth(font, "m") * strlen(s) / 2, 0));
189                 string(screen, p, screen->display->white, ZP, font, s);
190         }
191         flushimage(display, 1);
192
193         /* screen is now open and covered.  grab mouse and hold on tight */
194         procrfork(top, nil, 8*1024, RFFDG);
195         procrfork(grabmouse, nil, 8*1024, RFFDG);
196         procrfork(blanker, nil, 8*1024, RFFDG);
197
198         /* clear the cursor */
199         if((fd = open("/dev/cursor", OWRITE)) >= 0){
200                 memset(cbuf, 0, sizeof cbuf);
201                 write(fd, cbuf, sizeof cbuf);
202                 /* leave it open */
203         }
204 }
205
206 void
207 threadmain(int argc, char *argv[])
208 {
209         ARGBEGIN{
210         case 'd':
211                 debug++;
212                 break;
213         default:
214                 usage();
215         }ARGEND
216
217         if(argc != 0)
218                 usage();
219
220         lockscreen();
221         checkpassword();
222         threadexitsall(nil);
223 }