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-2024
15 Free Software Foundation, Inc.
17 This file is part of the Midnight Commander.
19 The Midnight Commander is free software: you can redistribute it
20 and/or modify it under the terms of the GNU General Public License as
21 published by the Free Software Foundation, either version 3 of the License,
22 or (at your option) any later version.
24 The Midnight Commander is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
29 You should have received a copy of the GNU General Public License
30 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 /* This code does _not_ need to be setuid root. However, it needs
34 read/write access to /dev/vcsa* (which is privileged
35 operation). You should create user vcsa, make cons.saver setuid
36 user vcsa, and make all vcsa's owned by user vcsa.
38 Seeing other peoples consoles is bad thing, but believe me, full
39 root is even worse. */
41 /** \file cons.saver.c
42 * \brief Source: general purpose Linux console screen save/restore server
44 * This code does _not_ need to be setuid root. However, it needs
45 * read/write access to /dev/vcsa* (which is privileged
46 * operation). You should create user vcsa, make cons.saver setuid
47 * user vcsa, and make all vcsa's owned by user vcsa.
48 * Seeing other peoples consoles is bad thing, but believe me, full
62 #include <sys/types.h>
64 #ifdef HAVE_SYS_IOCTL_H
65 #include <sys/ioctl.h>
72 #include "lib/unixcompat.h" /* STDERR_FILENO */
74 #define LINUX_CONS_SAVER_C
75 #include "cons.saver.h"
77 /*** global variables ****************************************************************************/
79 /*** file scope macro definitions ****************************************************************/
81 /*** file scope type declarations ****************************************************************/
83 /*** forward declarations (file scope functions) *************************************************/
85 /*** file scope variables ************************************************************************/
87 /* --------------------------------------------------------------------------------------------- */
88 /*** file scope functions ************************************************************************/
89 /* --------------------------------------------------------------------------------------------- */
92 send_contents (char *buffer
, unsigned int columns
, unsigned int rows
)
94 unsigned char begin_line
= 0, end_line
= 0;
95 unsigned int lastline
, lc_index
, x
;
96 unsigned char message
, outbuf
[1024], *p
;
99 lc_index
= 2 * rows
* columns
;
100 for (lastline
= rows
; lastline
> 0; lastline
--)
101 for (x
= 0; x
< columns
; x
++)
104 if (buffer
[lc_index
] != ' ')
109 message
= CONSOLE_CONTENTS
;
110 if (write (1, &message
, 1) != 1)
112 if (read (0, &begin_line
, 1) != 1)
114 if (read (0, &end_line
, 1) != 1)
116 if (begin_line
> lastline
)
117 begin_line
= lastline
;
118 if (end_line
> lastline
)
121 lc_index
= (end_line
- begin_line
) * columns
;
124 if (write (1, &bytes
, 2) != 2)
130 for (lc_index
= 2 * begin_line
* columns
; lc_index
< 2 * end_line
* columns
; lc_index
+= 2)
132 *p
++ = buffer
[lc_index
];
133 if (p
== outbuf
+ sizeof (outbuf
))
135 if (write (1, outbuf
, sizeof (outbuf
)) != sizeof (outbuf
))
142 if (write (1, outbuf
, p
- outbuf
) < (p
- outbuf
))
146 /* --------------------------------------------------------------------------------------------- */
148 static void __attribute__((noreturn
)) die (void)
150 unsigned char zero
= 0;
152 ret
= write (1, &zero
, 1);
157 /* --------------------------------------------------------------------------------------------- */
158 /*** public functions ****************************************************************************/
159 /* --------------------------------------------------------------------------------------------- */
162 main (int argc
, char **argv
)
164 unsigned char action
= 0, console_flag
= 3;
165 int console_fd
, vcsa_fd
, console_minor
, buffer_size
;
168 char *buffer
, *tty_name
, console_name
[16], vcsa_name
[16];
170 struct winsize winsz
;
172 close (STDERR_FILENO
);
178 if (strnlen (tty_name
, 15) == 15 || strncmp (tty_name
, "/dev/", 5))
185 if (seteuid (uid
) < 0)
187 console_fd
= open (tty_name
, O_RDONLY
);
190 if (fstat (console_fd
, &st
) < 0 || !S_ISCHR (st
.st_mode
))
192 #ifdef HAVE_STRUCT_STAT_ST_RDEV
193 if ((st
.st_rdev
& 0xff00) != 0x0400)
195 console_minor
= (int) (st
.st_rdev
& 0x00ff);
197 console_minor
= 1; /* FIXME */
199 if (console_minor
< 1 || console_minor
> 63)
201 if (st
.st_uid
!= uid
)
220 snprintf (console_name
, sizeof (console_name
), p
, console_minor
);
221 if (strncmp (console_name
, tty_name
, sizeof (console_name
)) != 0)
224 if (seteuid (euid
) < 0)
227 snprintf (vcsa_name
, sizeof (vcsa_name
), q
, console_minor
);
228 vcsa_fd
= open (vcsa_name
, O_RDWR
);
231 if (fstat (vcsa_fd
, &st
) < 0 || !S_ISCHR (st
.st_mode
))
234 if (seteuid (uid
) < 0)
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)
242 buffer_size
= 4 + 2 * winsz
.ws_col
* winsz
.ws_row
;
243 buffer
= calloc (buffer_size
, 1);
247 if (write (1, &console_flag
, 1) != 1)
250 while (console_flag
&& read (0, &action
, 1) == 1)
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)
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
)
272 if (seteuid (uid
) < 0)
275 case CONSOLE_CONTENTS
:
276 send_contents (buffer
+ 4, winsz
.ws_col
, winsz
.ws_row
);
282 if (write (1, &console_flag
, 1) != 1)
289 /* --------------------------------------------------------------------------------------------- */