Get “screen is terminating” without root

gnu-screenpermissions

I have installed screen on Fedora 19. When I test the command as root remotely through SSH, it works perfectly. For instance, if I enter screen a new terminal emulator is started and waits for commands. I can detach it, etc. However when I try to do the same once I am logged remotely through SSH as a standard user, the command terminates immediately. The only message I see is [screen is terminating].

Does someone have already had this problem? Is it related to bad permissions?

Update:

$ strace -e trace=file screen
execve("/usr/bin/screen", ["screen"], [/* 23 vars */]) = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libtinfo.so.5", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libutempter.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libcrypt.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libpam.so.0", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libfreebl3.so", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libaudit.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
access("/home/steam/.nethackrc", F_OK)  = -1 ENOENT (No such file or directory)
readlink("/proc/self/fd/0", "/dev/pts/0", 4095) = 10
stat("/dev/pts/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
lstat("/dev/pts/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
open("/var/run/utmp", O_RDONLY)         = 3
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3
open("/etc/shadow", O_RDONLY|O_CLOEXEC) = -1 EACCES (Permission denied)
readlink("/proc/self/fd/0", "/dev/pts/0", 4095) = 10
stat("/dev/pts/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
stat("/dev/pts/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
lstat("/dev/pts/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
stat("/var/run/screen", {st_mode=S_IFDIR|0775, st_size=60, ...}) = 0
Directory '/var/run/screen' must have mode 777.
+++ exited with 1 +++

I have tried to change permissions to 777 but then when I execute screen, I get:

Directory '/var/run/screen' must have mode 775.

Therefore, I have reverted my changes.

Best Answer

The flip-flopping between "must have mode 777" and "must have mode 775" is caused by strace.

screen is usually a setuid or setgid program. It gains extra privileges when it is executed, which is uses to create socket files and/or modify utmp.

When a process is being traced, setuid and setgid are disabled. The tracing process, controlled by the less-privileged user, can take over the traced process so it must run without its extra privileges to avoid giving the original user too much power.

screen detects whether it is being run with setuid privileges, setgid privileges, or neither, and adjusts its expectation of the directory permissions accordingly.

So this creates a class of problems that can't be easily debugged with strace.

But if you're root, there is a workaround! If the tracing process is running as root, then the traced process can gain privileges normally. So here's what you do:

  1. Open 2 new terminals
  2. In the first terminal, log in to the remote machine as root
  3. In the second terminal, log in to the remote machine as normal user
  4. Use ps to get the PID of the normal user's shell process in the second terminal
  5. In the first terminal, run strace -f -p SHELLPID
  6. In the second terminal, run screen and watch it fail
  7. In the first terminal, you now have the strace log you need to find out what's really wrong.

The key addition to the strace command is the -f option, which tells it to trace child processes. You need it to trace the screen that will be a child of the shell process you specified with -p.

I also like to use -ff and specify an output file with -o, as in

strace -ff -o /tmp/screentrace -p SHELLPID

which will create a separate output file for each child process. Afterward you read them with less /tmp/screentrace* and the result is usually cleaner than what you get using a single -f.

UPDATE

Now that I've seen the strace output, I don't know exactly what went wrong, but this line is the most surprising thing in the trace:

chown("/dev/pts/2", 1002, 5)            = -1 EPERM (Operation not permitted)

A few lines earlier, it created a pty, which was revealed by TIOCGPTN to be number 2.

open("/dev/ptmx", O_RDWR)               = 5
...
ioctl(5, TIOCGPTN, [2])                 = 0
stat("/dev/pts/2", {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 2), ...}) = 0

But it was unable to chown it. I don't know why that chown would fail, but the chown failure does give a plausible reason why screen gave up. You can get a little more information by adding -v to the strace options, and looking at the stat after the TIOCGPTN to see who owns the /dev/pts/ entry.

Related Question