普通用户无法进入screen状态的排查

一、现象描述

本文说的screen是”screen manager with VT100/ANSI terminal emulation”。完全没听过、没用过这玩意儿的,不必往下看。

在Ubuntu 22安装过程中创建的普通用户user1可以用screen;后来自己创建的user2不能用screen,也不报错,就是不进入screen状态;root可以screen。

二、排查结论

user2的实际名字是none,这是screen的保留关键字,在程序内有检查,有其他用途。普通用户名为none时,会触发意料之外的流程,导致none用户无法进入screen状态。这事儿可气在none执行screen时,静默结束,无任何报错。

只关心结论者到此止步。

三、排查过程

起初以为是权限问题,毕竟root可用,毕竟初创普通用户隶属多个特权组。将user2加入特权组,情况依旧。放狗、问GPT,都说是权限问题,GPT捏造出名为screen的特权组,建议将user2置入该组。再就是说动用setuid技术,给screen加s位。未测试s位,从排查结论看,本例即使用了s位,也解决不了。即使s位能解决,也不想用,我想知道为什么user1能用、user2不能用。

检查了几处权限设置,无异常

ls -l $(which screen)
ls -l $(tty)
ls -l /var/run/utmp
ls -l /var/run/screen/
ls -ld /var/run/screen/S-$USER

试图常规查看日志,无果

screen -L -Logfile /tmp/screenlog

接下来用strace观察user1、user2执行screen的过程

strace -v -ff -o /tmp/screen screen

这是我的常用strace参数组合,”-ff”是”–follow-forks –output-separately”的缩写格式。user1成功,生成一批screen.<pid>;user2失败,只有2个screen.<pid>。用BC比较它们,父进程无本质差异;第一个子进程有本质差异,user2在此有一行

write(1, “Could not create user info\r\n”, 28) = 28

此行只在strace时看到,stdout并无输出。拖源码回来看看

cd ~/src/
mkdir screen
cd screen/
apt-get source screen
tar cfj screen-4.9.0.tar.bz2 screen-4.9.0

回Windows中展开tar.bz2,7-Zip展开失败,说没有权限创建”symbolic link”;在WSL1中”tar xfj”展开成功。用Source Insight查看screen源码,搜前述错误信息,定位至

————————————————————————–
/*
* screen-4.9.0\screen.c
*/

freopen(“/dev/null”, “r”, stdin);
freopen(“/dev/null”, “w”, stdout);
freopen(“/dev/null”, “w”, stderr);

/*
* This guarantees that the session owner is listed, even when we
* start detached. From now on we should not refer to ‘LoginName’
* any more, use users->u_name instead.
*/
if ( UserAdd( LoginName, (char *)0, (struct acluser **)0 ) < 0 )
{
Panic( 0, “Could not create user info” );
}
————————————————————————–

stdout、stderr全部重定向到/dev/null,伪终端看不到Panic()的错误提示,小坑。

————————————————————————–
/*
* screen-4.9.0\acls.c
*
* Add a new user. His password may be NULL or “” if none. His name must not
* be “none”, as this represents the NULL-pointer when dealing with groups.
* He has default rights, determined by umask.
*/
int UserAdd ( name, pass, up )
{
if ( !up )
{
up = FindUserPtr( name );
}
if ( *up )
{
..
/*
* he is already there
*/
return 1;
}
/*
* “none” is a reserved word
*/
if ( strcmp( “none”, name ) )
{
*up = (struct acluser *)calloc( 1, sizeof(struct acluser) );
}
if ( !*up )
{
/*
* he still does not exist
*/
return -1;
}
————————————————————————–

UserAdd(“none”)必然失败,其内部要求用户名不得是”none”这个保留关键字,至此算是破案。

事实诸葛亮,既然none是screen的保留关键字,man手册应该有提,细看,果然。

————————————————————————–
aclgrp username [groupname]

A user is removed from all groups the special value none is used for groupname.
————————————————————————–

即是说,”aclgrp someuser none”,相当于”aclgrp someuser <all group>”。但man中并未明确警告勿用none做用户名。

理论指导实践,创建普通用户user3,避开none这个名字,user3可用screen,闭环。

四、如何判断处于screen中

有许多办法,此处只列其中比较简单易行的判断办法

位于screen中

$ pstree -s $$
systemd───sshd───sshd───sshd───bash───screen───screen───bash───pstree

$ echo $TERM
screen

$ echo $STY
6957.pts-1.Ubuntu-22

“Ctrl-A T”显示时间,具体操作是,按完Ctrl-A,保持Ctrl,松开A,再按T。

退出screen后

$ pstree -s $$
systemd───sshd───sshd───sshd───bash───pstree

$ echo $TERM
vt100

$ echo $STY

版权声明
本站“技术博客”所有内容的版权持有者为绿盟科技集团股份有限公司(“绿盟科技”)。作为分享技术资讯的平台,绿盟科技期待与广大用户互动交流,并欢迎在标明出处(绿盟科技-技术博客)及网址的情形下,全文转发。
上述情形之外的任何使用形式,均需提前向绿盟科技(010-68438880-5462)申请版权授权。如擅自使用,绿盟科技保留追责权利。同时,如因擅自使用博客内容引发法律纠纷,由使用者自行承担全部法律责任,与绿盟科技无关。

Spread the word. Share this post!

Meet The Author

C/ASM程序员