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