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))
149 die (void)
150 {
151 unsigned char zero = 0;
152 ssize_t ret;
153 ret = write (1, &zero, 1);
154 (void) ret;
155 exit (3);
156 }
157
158
159
160
161
162 int
163 main (int argc, char **argv)
164 {
165 unsigned char action = 0, console_flag = 3;
166 int console_fd, vcsa_fd, console_minor, buffer_size;
167 struct stat st;
168 uid_t uid, euid;
169 char *buffer, *tty_name, console_name[16], vcsa_name[16];
170 const char *p, *q;
171 struct winsize winsz;
172
173 close (STDERR_FILENO);
174
175 if (argc != 2)
176 die ();
177
178 tty_name = argv[1];
179 if (strnlen (tty_name, 15) == 15 || strncmp (tty_name, "/dev/", 5))
180 die ();
181
182 setsid ();
183 uid = getuid ();
184 euid = geteuid ();
185
186 if (seteuid (uid) < 0)
187 die ();
188 console_fd = open (tty_name, O_RDONLY);
189 if (console_fd < 0)
190 die ();
191 if (fstat (console_fd, &st) < 0 || !S_ISCHR (st.st_mode))
192 die ();
193 #ifdef HAVE_STRUCT_STAT_ST_RDEV
194 if ((st.st_rdev & 0xff00) != 0x0400)
195 die ();
196 console_minor = (int) (st.st_rdev & 0x00ff);
197 #else
198 console_minor = 1;
199 #endif
200 if (console_minor < 1 || console_minor > 63)
201 die ();
202 if (st.st_uid != uid)
203 die ();
204
205 switch (tty_name[5])
206 {
207 case 'v':
208
209 p = "/dev/vc/%d";
210 q = "/dev/vcc/a%d";
211 break;
212 case 't':
213
214 p = "/dev/tty%d";
215 q = "/dev/vcsa%d";
216 break;
217 default:
218 die ();
219 }
220
221 snprintf (console_name, sizeof (console_name), p, console_minor);
222 if (strncmp (console_name, tty_name, sizeof (console_name)) != 0)
223 die ();
224
225 if (seteuid (euid) < 0)
226 die ();
227
228 snprintf (vcsa_name, sizeof (vcsa_name), q, console_minor);
229 vcsa_fd = open (vcsa_name, O_RDWR);
230 if (vcsa_fd < 0)
231 die ();
232 if (fstat (vcsa_fd, &st) < 0 || !S_ISCHR (st.st_mode))
233 die ();
234
235 if (seteuid (uid) < 0)
236 die ();
237
238 winsz.ws_col = winsz.ws_row = 0;
239 if (ioctl (console_fd, TIOCGWINSZ, &winsz) < 0 || winsz.ws_col <= 0 || winsz.ws_row <= 0
240 || winsz.ws_col >= 256 || winsz.ws_row >= 256)
241 die ();
242
243 buffer_size = 4 + 2 * winsz.ws_col * winsz.ws_row;
244 buffer = calloc (buffer_size, 1);
245 if (buffer == NULL)
246 die ();
247
248 if (write (1, &console_flag, 1) != 1)
249 die ();
250
251 while (console_flag && read (0, &action, 1) == 1)
252 {
253 switch (action)
254 {
255 case CONSOLE_DONE:
256 console_flag = 0;
257 continue;
258 case CONSOLE_SAVE:
259 if (seteuid (euid) < 0 || lseek (vcsa_fd, 0, 0) != 0 || fstat (console_fd, &st) < 0
260 || st.st_uid != uid || read (vcsa_fd, buffer, buffer_size) != buffer_size
261 || fstat (console_fd, &st) < 0 || st.st_uid != uid)
262 memset (buffer, 0, buffer_size);
263 if (seteuid (uid) < 0)
264 die ();
265 break;
266 case CONSOLE_RESTORE:
267 if (seteuid (euid) >= 0 && lseek (vcsa_fd, 0, 0) == 0 && fstat (console_fd, &st) >= 0
268 && st.st_uid == uid)
269 if (write (vcsa_fd, buffer, buffer_size) != buffer_size)
270 die ();
271 if (seteuid (uid) < 0)
272 die ();
273 break;
274 case CONSOLE_CONTENTS:
275 send_contents (buffer + 4, winsz.ws_col, winsz.ws_row);
276 break;
277 default:
278 break;
279 }
280
281 if (write (1, &console_flag, 1) != 1)
282 die ();
283 }
284
285 exit (0);
286 }
287
288