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 static void
89 send_contents (char *buffer, unsigned int columns, unsigned int rows)
90 {
91 unsigned char begin_line = 0, end_line = 0;
92 unsigned int lastline, lc_index, x;
93 unsigned char message, outbuf[1024], *p;
94 unsigned short bytes;
95
96 lc_index = 2 * rows * columns;
97 for (lastline = rows; lastline > 0; lastline--)
98 for (x = 0; x < columns; x++)
99 {
100 lc_index -= 2;
101 if (buffer[lc_index] != ' ')
102 goto out;
103 }
104 out:
105
106 message = CONSOLE_CONTENTS;
107 if (write (1, &message, 1) != 1)
108 return;
109 if (read (0, &begin_line, 1) != 1)
110 return;
111 if (read (0, &end_line, 1) != 1)
112 return;
113 if (begin_line > lastline)
114 begin_line = lastline;
115 if (end_line > lastline)
116 end_line = lastline;
117
118 lc_index = (end_line - begin_line) * columns;
119 bytes = lc_index;
120
121 if (write (1, &bytes, 2) != 2)
122 return;
123 if (bytes == 0)
124 return;
125
126 p = outbuf;
127 for (lc_index = 2 * begin_line * columns; lc_index < 2 * end_line * columns; lc_index += 2)
128 {
129 *p++ = buffer[lc_index];
130 if (p == outbuf + sizeof (outbuf))
131 {
132 if (write (1, outbuf, sizeof (outbuf)) != sizeof (outbuf))
133 return;
134 p = outbuf;
135 }
136 }
137
138 if (p != outbuf)
139 if (write (1, outbuf, p - outbuf) < (p - outbuf))
140 return;
141 }
142
143
144
145 static void __attribute__ ((noreturn)) die (void)
146 {
147 unsigned char zero = 0;
148 ssize_t ret;
149 ret = write (1, &zero, 1);
150 (void) ret;
151 exit (3);
152 }
153
154
155
156
157
158 int
159 main (int argc, char **argv)
160 {
161 unsigned char action = 0, console_flag = 3;
162 int console_fd, vcsa_fd, console_minor, buffer_size;
163 struct stat st;
164 uid_t uid, euid;
165 char *buffer, *tty_name, console_name[16], vcsa_name[16];
166 const char *p, *q;
167 struct winsize winsz;
168
169 close (STDERR_FILENO);
170
171 if (argc != 2)
172 die ();
173
174 tty_name = argv[1];
175 if (strnlen (tty_name, 15) == 15 || strncmp (tty_name, "/dev/", 5))
176 die ();
177
178 setsid ();
179 uid = getuid ();
180 euid = geteuid ();
181
182 if (seteuid (uid) < 0)
183 die ();
184 console_fd = open (tty_name, O_RDONLY);
185 if (console_fd < 0)
186 die ();
187 if (fstat (console_fd, &st) < 0 || !S_ISCHR (st.st_mode))
188 die ();
189 #ifdef HAVE_STRUCT_STAT_ST_RDEV
190 if ((st.st_rdev & 0xff00) != 0x0400)
191 die ();
192 console_minor = (int) (st.st_rdev & 0x00ff);
193 #else
194 console_minor = 1;
195 #endif
196 if (console_minor < 1 || console_minor > 63)
197 die ();
198 if (st.st_uid != uid)
199 die ();
200
201 switch (tty_name[5])
202 {
203
204 case 'v':
205 p = "/dev/vc/%d";
206 q = "/dev/vcc/a%d";
207 break;
208
209 case 't':
210 p = "/dev/tty%d";
211 q = "/dev/vcsa%d";
212 break;
213 default:
214 die ();
215 }
216
217 snprintf (console_name, sizeof (console_name), p, console_minor);
218 if (strncmp (console_name, tty_name, sizeof (console_name)) != 0)
219 die ();
220
221 if (seteuid (euid) < 0)
222 die ();
223
224 snprintf (vcsa_name, sizeof (vcsa_name), q, console_minor);
225 vcsa_fd = open (vcsa_name, O_RDWR);
226 if (vcsa_fd < 0)
227 die ();
228 if (fstat (vcsa_fd, &st) < 0 || !S_ISCHR (st.st_mode))
229 die ();
230
231 if (seteuid (uid) < 0)
232 die ();
233
234 winsz.ws_col = winsz.ws_row = 0;
235 if (ioctl (console_fd, TIOCGWINSZ, &winsz) < 0
236 || winsz.ws_col <= 0 || winsz.ws_row <= 0 || winsz.ws_col >= 256 || winsz.ws_row >= 256)
237 die ();
238
239 buffer_size = 4 + 2 * winsz.ws_col * winsz.ws_row;
240 buffer = calloc (buffer_size, 1);
241 if (buffer == NULL)
242 die ();
243
244 if (write (1, &console_flag, 1) != 1)
245 die ();
246
247 while (console_flag && read (0, &action, 1) == 1)
248 {
249 switch (action)
250 {
251 case CONSOLE_DONE:
252 console_flag = 0;
253 continue;
254 case CONSOLE_SAVE:
255 if (seteuid (euid) < 0
256 || lseek (vcsa_fd, 0, 0) != 0
257 || fstat (console_fd, &st) < 0 || st.st_uid != uid
258 || read (vcsa_fd, buffer, buffer_size) != buffer_size
259 || fstat (console_fd, &st) < 0 || st.st_uid != uid)
260 memset (buffer, 0, buffer_size);
261 if (seteuid (uid) < 0)
262 die ();
263 break;
264 case CONSOLE_RESTORE:
265 if (seteuid (euid) >= 0
266 && lseek (vcsa_fd, 0, 0) == 0 && fstat (console_fd, &st) >= 0 && st.st_uid == uid)
267 if (write (vcsa_fd, buffer, buffer_size) != buffer_size)
268 die ();
269 if (seteuid (uid) < 0)
270 die ();
271 break;
272 case CONSOLE_CONTENTS:
273 send_contents (buffer + 4, winsz.ws_col, winsz.ws_row);
274 break;
275 default:
276 break;
277 }
278
279 if (write (1, &console_flag, 1) != 1)
280 die ();
281 }
282
283 exit (0);
284 }
285
286