2004-10-05 11:14:09 +04:00
|
|
|
/* This program should be setuid vcsa and /dev/vcsa* should be
|
|
|
|
owned by the same user too.
|
|
|
|
Partly rewritten by Jakub Jelinek <jakub@redhat.com>. */
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
/* General purpose Linux console screen save/restore server
|
2007-09-26 14:22:25 +04:00
|
|
|
Copyright (C) 1994, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
|
|
|
2006, 2007 Free Software Foundation, Inc.
|
1998-02-27 07:54:42 +03:00
|
|
|
Original idea from Unix Interactive Tools version 3.2b (tty.c)
|
|
|
|
This code requires root privileges.
|
2004-10-05 11:14:09 +04:00
|
|
|
You may want to make the cons.saver setuid root.
|
|
|
|
The code should be safe even if it is setuid but who knows?
|
1998-02-27 07:54:42 +03:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2005-05-27 07:35:10 +04:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
/* This code does _not_ need to be setuid root. However, it needs
|
|
|
|
read/write access to /dev/vcsa* (which is priviledged
|
|
|
|
operation). You should create user vcsa, make cons.saver setuid
|
|
|
|
user vcsa, and make all vcsa's owned by user vcsa.
|
1999-05-12 15:48:11 +04:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
Seeing other peoples consoles is bad thing, but believe me, full
|
|
|
|
root is even worse. */
|
|
|
|
|
2009-02-06 17:46:15 +03:00
|
|
|
/** \file cons.saver.c
|
2009-02-05 21:28:18 +03:00
|
|
|
* \brief Source: general purpose Linux console screen save/restore server
|
|
|
|
*
|
|
|
|
* This code does _not_ need to be setuid root. However, it needs
|
|
|
|
* read/write access to /dev/vcsa* (which is priviledged
|
|
|
|
* operation). You should create user vcsa, make cons.saver setuid
|
|
|
|
* user vcsa, and make all vcsa's owned by user vcsa.
|
|
|
|
* Seeing other peoples consoles is bad thing, but believe me, full
|
|
|
|
* root is even worse.
|
|
|
|
*/
|
|
|
|
|
2006-02-21 17:02:11 +03:00
|
|
|
#include <config.h>
|
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
1998-02-27 07:54:42 +03:00
|
|
|
#endif
|
2005-02-08 12:04:03 +03:00
|
|
|
|
1998-02-27 07:54:42 +03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2000-11-16 20:09:08 +03:00
|
|
|
#include <string.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
2005-02-08 12:04:03 +03:00
|
|
|
#include <fcntl.h>
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
|
|
#include <termios.h>
|
|
|
|
#endif
|
|
|
|
#include <unistd.h>
|
2001-11-29 23:28:48 +03:00
|
|
|
|
|
|
|
#define LINUX_CONS_SAVER_C
|
1998-02-27 07:54:42 +03:00
|
|
|
#include "cons.saver.h"
|
2009-05-24 13:39:14 +04:00
|
|
|
#include "../src/tty/win.h"
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-22 03:08:28 +04:00
|
|
|
static void
|
2004-10-05 11:14:09 +04:00
|
|
|
send_contents (char *buffer, unsigned int columns, unsigned int rows)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-10-05 11:14:09 +04:00
|
|
|
unsigned char begin_line = 0, end_line = 0;
|
|
|
|
unsigned int lastline, index, x;
|
|
|
|
unsigned char message, outbuf[1024], *p;
|
|
|
|
unsigned short bytes;
|
|
|
|
|
|
|
|
index = 2 * rows * columns;
|
|
|
|
for (lastline = rows; lastline > 0; lastline--)
|
|
|
|
for (x = 0; x < columns; x++)
|
|
|
|
{
|
|
|
|
index -= 2;
|
|
|
|
if (buffer [index] != ' ')
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
|
|
|
|
message = CONSOLE_CONTENTS;
|
|
|
|
write (1, &message, 1);
|
|
|
|
|
|
|
|
read (0, &begin_line, 1);
|
|
|
|
read (0, &end_line, 1);
|
|
|
|
if (begin_line > lastline)
|
|
|
|
begin_line = lastline;
|
|
|
|
if (end_line > lastline)
|
|
|
|
end_line = lastline;
|
|
|
|
|
|
|
|
index = (end_line - begin_line) * columns;
|
|
|
|
bytes = index;
|
|
|
|
if (index != bytes)
|
|
|
|
bytes = 0;
|
|
|
|
write (1, &bytes, 2);
|
|
|
|
if (! bytes)
|
|
|
|
return;
|
|
|
|
|
|
|
|
p = outbuf;
|
|
|
|
for (index = 2 * begin_line * columns;
|
|
|
|
index < 2 * end_line * columns;
|
|
|
|
index += 2)
|
|
|
|
{
|
|
|
|
*p++ = buffer [index];
|
|
|
|
if (p == outbuf + sizeof (outbuf))
|
|
|
|
{
|
|
|
|
write (1, outbuf, sizeof (outbuf));
|
|
|
|
p = outbuf;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
2002-07-29 09:59:07 +04:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
if (p != outbuf)
|
|
|
|
write (1, outbuf, p - outbuf);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2004-10-22 03:08:28 +04:00
|
|
|
static void __attribute__ ((noreturn))
|
2004-10-05 11:14:09 +04:00
|
|
|
die (void)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-10-05 11:14:09 +04:00
|
|
|
unsigned char zero = 0;
|
|
|
|
write (1, &zero, 1);
|
|
|
|
exit (3);
|
1998-02-27 07:54:42 +03:00
|
|
|
}
|
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
1998-02-27 07:54:42 +03:00
|
|
|
{
|
2004-10-05 11:14:09 +04:00
|
|
|
unsigned char action = 0, console_flag = 3;
|
|
|
|
int console_fd, vcsa_fd, console_minor, buffer_size;
|
|
|
|
struct stat st;
|
|
|
|
uid_t uid, euid;
|
2009-07-15 22:53:13 +04:00
|
|
|
char *buffer, *tty_name, console_name [16], vcsa_name [16];
|
|
|
|
const char *p, *q;
|
2004-10-05 11:14:09 +04:00
|
|
|
struct winsize winsz;
|
|
|
|
|
|
|
|
close (2);
|
|
|
|
|
|
|
|
if (argc != 2)
|
|
|
|
die ();
|
|
|
|
|
|
|
|
tty_name = argv [1];
|
|
|
|
if (strnlen (tty_name, 15) == 15
|
|
|
|
|| strncmp (tty_name, "/dev/", 5))
|
|
|
|
die ();
|
|
|
|
|
|
|
|
setsid ();
|
|
|
|
uid = getuid ();
|
|
|
|
euid = geteuid ();
|
|
|
|
|
|
|
|
if (seteuid (uid) < 0)
|
|
|
|
die ();
|
|
|
|
console_fd = open (tty_name, O_RDONLY);
|
|
|
|
if (console_fd < 0)
|
|
|
|
die ();
|
|
|
|
if (fstat (console_fd, &st) < 0 || ! S_ISCHR (st.st_mode))
|
|
|
|
die ();
|
|
|
|
if ((st.st_rdev & 0xff00) != 0x0400)
|
|
|
|
die ();
|
|
|
|
console_minor = (int) (st.st_rdev & 0x00ff);
|
|
|
|
if (console_minor < 1 || console_minor > 63)
|
|
|
|
die ();
|
|
|
|
if (st.st_uid != uid)
|
|
|
|
die ();
|
|
|
|
|
|
|
|
switch (tty_name [5])
|
2001-07-06 23:24:27 +04:00
|
|
|
{
|
2004-10-05 11:14:09 +04:00
|
|
|
/* devfs */
|
|
|
|
case 'v': p = "/dev/vc/%d"; q = "/dev/vcc/a%d"; break;
|
|
|
|
/* /dev/ttyN */
|
|
|
|
case 't': p = "/dev/tty%d"; q = "/dev/vcsa%d"; break;
|
|
|
|
default: die (); break;
|
2001-07-06 23:24:27 +04:00
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
snprintf (console_name, sizeof (console_name), p, console_minor);
|
|
|
|
if (strncmp (console_name, tty_name, sizeof (console_name)) != 0)
|
|
|
|
die ();
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
if (seteuid (euid) < 0)
|
|
|
|
die ();
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
snprintf (vcsa_name, sizeof (vcsa_name), q, console_minor);
|
|
|
|
vcsa_fd = open (vcsa_name, O_RDWR);
|
|
|
|
if (vcsa_fd < 0)
|
|
|
|
die ();
|
|
|
|
if (fstat (vcsa_fd, &st) < 0 || ! S_ISCHR (st.st_mode))
|
|
|
|
die ();
|
2002-07-29 09:59:07 +04:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
if (seteuid (uid) < 0)
|
|
|
|
die ();
|
2002-07-28 12:52:27 +04:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
winsz.ws_col = winsz.ws_row = 0;
|
|
|
|
if (ioctl (console_fd, TIOCGWINSZ, &winsz) < 0
|
|
|
|
|| winsz.ws_col <= 0 || winsz.ws_row <= 0
|
|
|
|
|| winsz.ws_col >= 256 || winsz.ws_row >= 256)
|
|
|
|
die ();
|
1999-05-12 15:48:11 +04:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
buffer_size = 4 + 2 * winsz.ws_col * winsz.ws_row;
|
|
|
|
buffer = calloc (buffer_size, 1);
|
|
|
|
if (buffer == NULL)
|
|
|
|
die ();
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
write (1, &console_flag, 1);
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
while (console_flag && read (0, &action, 1) == 1)
|
|
|
|
{
|
|
|
|
switch (action)
|
|
|
|
{
|
1998-02-27 07:54:42 +03:00
|
|
|
case CONSOLE_DONE:
|
2004-10-05 11:14:09 +04:00
|
|
|
console_flag = 0;
|
|
|
|
continue;
|
1998-02-27 07:54:42 +03:00
|
|
|
case CONSOLE_SAVE:
|
2004-10-05 11:14:09 +04:00
|
|
|
if (seteuid (euid) < 0
|
|
|
|
|| lseek (vcsa_fd, 0, 0) != 0
|
|
|
|
|| fstat (console_fd, &st) < 0 || st.st_uid != uid
|
|
|
|
|| read (vcsa_fd, buffer, buffer_size) != buffer_size
|
|
|
|
|| fstat (console_fd, &st) < 0 || st.st_uid != uid)
|
|
|
|
memset (buffer, 0, buffer_size);
|
|
|
|
if (seteuid (uid) < 0)
|
|
|
|
die ();
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
case CONSOLE_RESTORE:
|
2004-10-05 11:14:09 +04:00
|
|
|
if (seteuid (euid) >= 0
|
|
|
|
&& lseek (vcsa_fd, 0, 0) == 0
|
|
|
|
&& fstat (console_fd, &st) >= 0 && st.st_uid == uid)
|
|
|
|
write (vcsa_fd, buffer, buffer_size);
|
|
|
|
if (seteuid (uid) < 0)
|
|
|
|
die ();
|
|
|
|
break;
|
1998-02-27 07:54:42 +03:00
|
|
|
case CONSOLE_CONTENTS:
|
2004-10-05 11:14:09 +04:00
|
|
|
send_contents (buffer + 4, winsz.ws_col, winsz.ws_row);
|
|
|
|
break;
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
write (1, &console_flag, 1);
|
|
|
|
}
|
1998-02-27 07:54:42 +03:00
|
|
|
|
2004-10-05 11:14:09 +04:00
|
|
|
exit (0);
|
|
|
|
}
|