Try fix of compile warnings about assigned but unused variables
[midnight-commander.git] / src / consaver / cons.saver.c
blobba88445ae9622e7a8a370cbea50e870841e90e95
1 /*
2 General purpose Linux console screen save/restore server
4 This program should be setuid vcsa and /dev/vcsa* should be
5 owned by the same user too.
7 Original idea from Unix Interactive Tools version 3.2b (tty.c)
8 This code requires root privileges.
9 You may want to make the cons.saver setuid root.
10 The code should be safe even if it is setuid but who knows?
12 Partly rewritten by Jakub Jelinek <jakub@redhat.com>.
14 Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
15 2006, 2007, 2011
16 The Free Software Foundation, Inc.
18 This file is part of the Midnight Commander.
20 The Midnight Commander is free software: you can redistribute it
21 and/or modify it under the terms of the GNU General Public License as
22 published by the Free Software Foundation, either version 3 of the License,
23 or (at your option) any later version.
25 The Midnight Commander is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program. If not, see <http://www.gnu.org/licenses/>.
34 /* This code does _not_ need to be setuid root. However, it needs
35 read/write access to /dev/vcsa* (which is priviledged
36 operation). You should create user vcsa, make cons.saver setuid
37 user vcsa, and make all vcsa's owned by user vcsa.
39 Seeing other peoples consoles is bad thing, but believe me, full
40 root is even worse. */
42 /** \file cons.saver.c
43 * \brief Source: general purpose Linux console screen save/restore server
45 * This code does _not_ need to be setuid root. However, it needs
46 * read/write access to /dev/vcsa* (which is priviledged
47 * operation). You should create user vcsa, make cons.saver setuid
48 * user vcsa, and make all vcsa's owned by user vcsa.
49 * Seeing other peoples consoles is bad thing, but believe me, full
50 * root is even worse.
53 #include <config.h>
55 #ifndef _GNU_SOURCE
56 #define _GNU_SOURCE
57 #endif
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #ifdef HAVE_SYS_IOCTL_H
66 #include <sys/ioctl.h>
67 #endif
68 #include <fcntl.h>
69 #include <termios.h>
70 #include <unistd.h>
72 #define LINUX_CONS_SAVER_C
73 #include "cons.saver.h"
75 /*** global variables ****************************************************************************/
77 /*** file scope macro definitions ****************************************************************/
79 /*** file scope type declarations ****************************************************************/
81 /*** file scope variables ************************************************************************/
83 /*** file scope functions ************************************************************************/
84 /* --------------------------------------------------------------------------------------------- */
86 static void
87 send_contents (char *buffer, unsigned int columns, unsigned int rows)
89 unsigned char begin_line = 0, end_line = 0;
90 unsigned int lastline, lc_index, x;
91 unsigned char message, outbuf[1024], *p;
92 unsigned short bytes;
94 lc_index = 2 * rows * columns;
95 for (lastline = rows; lastline > 0; lastline--)
96 for (x = 0; x < columns; x++)
98 lc_index -= 2;
99 if (buffer[lc_index] != ' ')
100 goto out;
102 out:
104 message = CONSOLE_CONTENTS;
105 if (write (1, &message, 1) != 1)
106 return;
107 if (read (0, &begin_line, 1) != 1)
108 return;
109 if (read (0, &end_line, 1) != 1)
110 return;
111 if (begin_line > lastline)
112 begin_line = lastline;
113 if (end_line > lastline)
114 end_line = lastline;
116 lc_index = (end_line - begin_line) * columns;
117 bytes = lc_index;
119 if (write (1, &bytes, 2) != 2)
120 return;
121 if (bytes == 0)
122 return;
124 p = outbuf;
125 for (lc_index = 2 * begin_line * columns; lc_index < 2 * end_line * columns; lc_index += 2)
127 *p++ = buffer[lc_index];
128 if (p == outbuf + sizeof (outbuf))
130 if (write (1, outbuf, sizeof (outbuf)) != sizeof (outbuf))
131 return;
132 p = outbuf;
136 if (p != outbuf)
137 if (write (1, outbuf, p - outbuf) < (p - outbuf))
138 return;
141 /* --------------------------------------------------------------------------------------------- */
143 static void __attribute__ ((noreturn)) die (void)
145 unsigned char zero = 0;
146 (void) write (1, &zero, 1);
147 exit (3);
150 /* --------------------------------------------------------------------------------------------- */
151 /*** public functions ****************************************************************************/
152 /* --------------------------------------------------------------------------------------------- */
155 main (int argc, char **argv)
157 unsigned char action = 0, console_flag = 3;
158 int console_fd, vcsa_fd, console_minor, buffer_size;
159 struct stat st;
160 uid_t uid, euid;
161 char *buffer, *tty_name, console_name[16], vcsa_name[16];
162 const char *p, *q;
163 struct winsize winsz;
165 close (2);
167 if (argc != 2)
168 die ();
170 tty_name = argv[1];
171 if (strnlen (tty_name, 15) == 15 || strncmp (tty_name, "/dev/", 5))
172 die ();
174 setsid ();
175 uid = getuid ();
176 euid = geteuid ();
178 if (seteuid (uid) < 0)
179 die ();
180 console_fd = open (tty_name, O_RDONLY);
181 if (console_fd < 0)
182 die ();
183 if (fstat (console_fd, &st) < 0 || !S_ISCHR (st.st_mode))
184 die ();
185 if ((st.st_rdev & 0xff00) != 0x0400)
186 die ();
187 console_minor = (int) (st.st_rdev & 0x00ff);
188 if (console_minor < 1 || console_minor > 63)
189 die ();
190 if (st.st_uid != uid)
191 die ();
193 switch (tty_name[5])
195 /* devfs */
196 case 'v':
197 p = "/dev/vc/%d";
198 q = "/dev/vcc/a%d";
199 break;
200 /* /dev/ttyN */
201 case 't':
202 p = "/dev/tty%d";
203 q = "/dev/vcsa%d";
204 break;
205 default:
206 die ();
207 break;
210 snprintf (console_name, sizeof (console_name), p, console_minor);
211 if (strncmp (console_name, tty_name, sizeof (console_name)) != 0)
212 die ();
214 if (seteuid (euid) < 0)
215 die ();
217 snprintf (vcsa_name, sizeof (vcsa_name), q, console_minor);
218 vcsa_fd = open (vcsa_name, O_RDWR);
219 if (vcsa_fd < 0)
220 die ();
221 if (fstat (vcsa_fd, &st) < 0 || !S_ISCHR (st.st_mode))
222 die ();
224 if (seteuid (uid) < 0)
225 die ();
227 winsz.ws_col = winsz.ws_row = 0;
228 if (ioctl (console_fd, TIOCGWINSZ, &winsz) < 0
229 || winsz.ws_col <= 0 || winsz.ws_row <= 0 || winsz.ws_col >= 256 || winsz.ws_row >= 256)
230 die ();
232 buffer_size = 4 + 2 * winsz.ws_col * winsz.ws_row;
233 buffer = calloc (buffer_size, 1);
234 if (buffer == NULL)
235 die ();
237 if (write (1, &console_flag, 1) != 1)
238 die ();
240 while (console_flag && read (0, &action, 1) == 1)
242 switch (action)
244 case CONSOLE_DONE:
245 console_flag = 0;
246 continue;
247 case CONSOLE_SAVE:
248 if (seteuid (euid) < 0
249 || lseek (vcsa_fd, 0, 0) != 0
250 || fstat (console_fd, &st) < 0 || st.st_uid != uid
251 || read (vcsa_fd, buffer, buffer_size) != buffer_size
252 || fstat (console_fd, &st) < 0 || st.st_uid != uid)
253 memset (buffer, 0, buffer_size);
254 if (seteuid (uid) < 0)
255 die ();
256 break;
257 case CONSOLE_RESTORE:
258 if (seteuid (euid) >= 0
259 && lseek (vcsa_fd, 0, 0) == 0 && fstat (console_fd, &st) >= 0 && st.st_uid == uid)
260 if (write (vcsa_fd, buffer, buffer_size) != buffer_size)
261 die ();
262 if (seteuid (uid) < 0)
263 die ();
264 break;
265 case CONSOLE_CONTENTS:
266 send_contents (buffer + 4, winsz.ws_col, winsz.ws_row);
267 break;
270 if (write (1, &console_flag, 1) != 1)
271 die ();
274 exit (0);
277 /* --------------------------------------------------------------------------------------------- */