This source file includes following definitions.
- send_contents
- die
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 #include <config.h>
53
54 #ifndef _GNU_SOURCE
55 #define _GNU_SOURCE
56 #endif
57
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <string.h>
61
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #ifdef HAVE_SYS_IOCTL_H
65 #include <sys/ioctl.h>
66 #endif
67 #ifdef HAVE_FCNTL_H
68 #include <fcntl.h>
69 #endif
70 #include <termios.h>
71
72 #include "lib/unixcompat.h"
73
74 #define LINUX_CONS_SAVER_C
75 #include "cons.saver.h"
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 static void
92 send_contents (char *buffer, unsigned int columns, unsigned int rows)
93 {
94 unsigned char begin_line = 0, end_line = 0;
95 unsigned int lastline, lc_index, x;
96 unsigned char message, outbuf[1024], *p;
97 unsigned short bytes;
98
99 lc_index = 2 * rows * columns;
100 for (lastline = rows; lastline > 0; lastline--)
101 for (x = 0; x < columns; x++)
102 {
103 lc_index -= 2;
104 if (buffer[lc_index] != ' ')
105 goto out;
106 }
107 out:
108
109 message = CONSOLE_CONTENTS;
110 if (write (1, &message, 1) != 1)
111 return;
112 if (read (0, &begin_line, 1) != 1)
113 return;
114 if (read (0, &end_line, 1) != 1)
115 return;
116 if (begin_line > lastline)
117 begin_line = lastline;
118 if (end_line > lastline)
119 end_line = lastline;
120
121 lc_index = (end_line - begin_line) * columns;
122 bytes = lc_index;
123
124 if (write (1, &bytes, 2) != 2)
125 return;
126 if (bytes == 0)
127 return;
128
129 p = outbuf;
130 for (lc_index = 2 * begin_line * columns; lc_index < 2 * end_line * columns; lc_index += 2)
131 {
132 *p++ = buffer[lc_index];
133 if (p == outbuf + sizeof (outbuf))
134 {
135 if (write (1, outbuf, sizeof (outbuf)) != sizeof (outbuf))
136 return;
137 p = outbuf;
138 }
139 }
140
141 if (p != outbuf)
142 if (write (1, outbuf, p - outbuf) < (p - outbuf))
143 return;
144 }
145
146
147
148 static void __attribute__((noreturn)) die (void)
149 {
150 unsigned char zero = 0;
151 ssize_t ret;
152 ret = write (1, &zero, 1);
153 (void) ret;
154 exit (3);
155 }
156
157
158
159
160
161 int
162 main (int argc, char **argv)
163 {
164 unsigned char action = 0, console_flag = 3;
165 int console_fd, vcsa_fd, console_minor, buffer_size;
166 struct stat st;
167 uid_t uid, euid;
168 char *buffer, *tty_name, console_name[16], vcsa_name[16];
169 const char *p, *q;
170 struct winsize winsz;
171
172 close (STDERR_FILENO);
173
174 if (argc != 2)
175 die ();
176
177 tty_name = argv[1];
178 if (strnlen (tty_name, 15) == 15 || strncmp (tty_name, "/dev/", 5))
179 die ();
180
181 setsid ();
182 uid = getuid ();
183 euid = geteuid ();
184
185 if (seteuid (uid) < 0)
186 die ();
187 console_fd = open (tty_name, O_RDONLY);
188 if (console_fd < 0)
189 die ();
190 if (fstat (console_fd, &st) < 0 || !S_ISCHR (st.st_mode))
191 die ();
192 #ifdef HAVE_STRUCT_STAT_ST_RDEV
193 if ((st.st_rdev & 0xff00) != 0x0400)
194 die ();
195 console_minor = (int) (st.st_rdev & 0x00ff);
196 #else
197 console_minor = 1;
198 #endif
199 if (console_minor < 1 || console_minor > 63)
200 die ();
201 if (st.st_uid != uid)
202 die ();
203
204 switch (tty_name[5])
205 {
206
207 case 'v':
208 p = "/dev/vc/%d";
209 q = "/dev/vcc/a%d";
210 break;
211
212 case 't':
213 p = "/dev/tty%d";
214 q = "/dev/vcsa%d";
215 break;
216 default:
217 die ();
218 }
219
220 snprintf (console_name, sizeof (console_name), p, console_minor);
221 if (strncmp (console_name, tty_name, sizeof (console_name)) != 0)
222 die ();
223
224 if (seteuid (euid) < 0)
225 die ();
226
227 snprintf (vcsa_name, sizeof (vcsa_name), q, console_minor);
228 vcsa_fd = open (vcsa_name, O_RDWR);
229 if (vcsa_fd < 0)
230 die ();
231 if (fstat (vcsa_fd, &st) < 0 || !S_ISCHR (st.st_mode))
232 die ();
233
234 if (seteuid (uid) < 0)
235 die ();
236
237 winsz.ws_col = winsz.ws_row = 0;
238 if (ioctl (console_fd, TIOCGWINSZ, &winsz) < 0
239 || winsz.ws_col <= 0 || winsz.ws_row <= 0 || winsz.ws_col >= 256 || winsz.ws_row >= 256)
240 die ();
241
242 buffer_size = 4 + 2 * winsz.ws_col * winsz.ws_row;
243 buffer = calloc (buffer_size, 1);
244 if (buffer == NULL)
245 die ();
246
247 if (write (1, &console_flag, 1) != 1)
248 die ();
249
250 while (console_flag && read (0, &action, 1) == 1)
251 {
252 switch (action)
253 {
254 case CONSOLE_DONE:
255 console_flag = 0;
256 continue;
257 case CONSOLE_SAVE:
258 if (seteuid (euid) < 0
259 || lseek (vcsa_fd, 0, 0) != 0
260 || fstat (console_fd, &st) < 0 || st.st_uid != uid
261 || read (vcsa_fd, buffer, buffer_size) != buffer_size
262 || fstat (console_fd, &st) < 0 || st.st_uid != uid)
263 memset (buffer, 0, buffer_size);
264 if (seteuid (uid) < 0)
265 die ();
266 break;
267 case CONSOLE_RESTORE:
268 if (seteuid (euid) >= 0
269 && lseek (vcsa_fd, 0, 0) == 0 && fstat (console_fd, &st) >= 0 && st.st_uid == uid)
270 if (write (vcsa_fd, buffer, buffer_size) != buffer_size)
271 die ();
272 if (seteuid (uid) < 0)
273 die ();
274 break;
275 case CONSOLE_CONTENTS:
276 send_contents (buffer + 4, winsz.ws_col, winsz.ws_row);
277 break;
278 default:
279 break;
280 }
281
282 if (write (1, &console_flag, 1) != 1)
283 die ();
284 }
285
286 exit (0);
287 }
288
289