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,
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
63 #include <sys/types.h>
65 #ifdef HAVE_SYS_IOCTL_H
66 #include <sys/ioctl.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 /* --------------------------------------------------------------------------------------------- */
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
;
94 lc_index
= 2 * rows
* columns
;
95 for (lastline
= rows
; lastline
> 0; lastline
--)
96 for (x
= 0; x
< columns
; x
++)
99 if (buffer
[lc_index
] != ' ')
104 message
= CONSOLE_CONTENTS
;
105 if (write (1, &message
, 1) != 1)
107 if (read (0, &begin_line
, 1) != 1)
109 if (read (0, &end_line
, 1) != 1)
111 if (begin_line
> lastline
)
112 begin_line
= lastline
;
113 if (end_line
> lastline
)
116 lc_index
= (end_line
- begin_line
) * columns
;
119 if (write (1, &bytes
, 2) != 2)
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
))
137 if (write (1, outbuf
, p
- outbuf
) < (p
- outbuf
))
141 /* --------------------------------------------------------------------------------------------- */
143 static void __attribute__ ((noreturn
)) die (void)
145 unsigned char zero
= 0;
147 ret
= write (1, &zero
, 1);
152 /* --------------------------------------------------------------------------------------------- */
153 /*** public functions ****************************************************************************/
154 /* --------------------------------------------------------------------------------------------- */
157 main (int argc
, char **argv
)
159 unsigned char action
= 0, console_flag
= 3;
160 int console_fd
, vcsa_fd
, console_minor
, buffer_size
;
163 char *buffer
, *tty_name
, console_name
[16], vcsa_name
[16];
165 struct winsize winsz
;
173 if (strnlen (tty_name
, 15) == 15 || strncmp (tty_name
, "/dev/", 5))
180 if (seteuid (uid
) < 0)
182 console_fd
= open (tty_name
, O_RDONLY
);
185 if (fstat (console_fd
, &st
) < 0 || !S_ISCHR (st
.st_mode
))
187 if ((st
.st_rdev
& 0xff00) != 0x0400)
189 console_minor
= (int) (st
.st_rdev
& 0x00ff);
190 if (console_minor
< 1 || console_minor
> 63)
192 if (st
.st_uid
!= uid
)
212 snprintf (console_name
, sizeof (console_name
), p
, console_minor
);
213 if (strncmp (console_name
, tty_name
, sizeof (console_name
)) != 0)
216 if (seteuid (euid
) < 0)
219 snprintf (vcsa_name
, sizeof (vcsa_name
), q
, console_minor
);
220 vcsa_fd
= open (vcsa_name
, O_RDWR
);
223 if (fstat (vcsa_fd
, &st
) < 0 || !S_ISCHR (st
.st_mode
))
226 if (seteuid (uid
) < 0)
229 winsz
.ws_col
= winsz
.ws_row
= 0;
230 if (ioctl (console_fd
, TIOCGWINSZ
, &winsz
) < 0
231 || winsz
.ws_col
<= 0 || winsz
.ws_row
<= 0 || winsz
.ws_col
>= 256 || winsz
.ws_row
>= 256)
234 buffer_size
= 4 + 2 * winsz
.ws_col
* winsz
.ws_row
;
235 buffer
= calloc (buffer_size
, 1);
239 if (write (1, &console_flag
, 1) != 1)
242 while (console_flag
&& read (0, &action
, 1) == 1)
250 if (seteuid (euid
) < 0
251 || lseek (vcsa_fd
, 0, 0) != 0
252 || fstat (console_fd
, &st
) < 0 || st
.st_uid
!= uid
253 || read (vcsa_fd
, buffer
, buffer_size
) != buffer_size
254 || fstat (console_fd
, &st
) < 0 || st
.st_uid
!= uid
)
255 memset (buffer
, 0, buffer_size
);
256 if (seteuid (uid
) < 0)
259 case CONSOLE_RESTORE
:
260 if (seteuid (euid
) >= 0
261 && lseek (vcsa_fd
, 0, 0) == 0 && fstat (console_fd
, &st
) >= 0 && st
.st_uid
== uid
)
262 if (write (vcsa_fd
, buffer
, buffer_size
) != buffer_size
)
264 if (seteuid (uid
) < 0)
267 case CONSOLE_CONTENTS
:
268 send_contents (buffer
+ 4, winsz
.ws_col
, winsz
.ws_row
);
272 if (write (1, &console_flag
, 1) != 1)
279 /* --------------------------------------------------------------------------------------------- */