如何找出进程启动时使用的原始用户名?

4

有一个 perl 脚本需要以 root 用户身份运行,但我们必须确保运行脚本的用户在最初登录时没有作为用户 'foo' 登录,因为在脚本中它将被删除。

那么我该如何找出该用户是否曾经在此期间模拟过 'foo' 用户,即使她已经多次 su-ed?

我发现一个有趣的 perl 脚本在调用以下两个 shell 脚本,但我认为这仅适用于 Solaris。

my $shell_parent = 
`ps -ef | grep -v grep | awk \'{print \$2\" \"\$3}\' | egrep \"^@_\" | awk \'{print \$2}'`;

my $parent_owner = 
`ps -ef | grep -v grep | awk \'{print \$1\" \"\$2}\' | grep @_ | awk \'{print \$1}\'`;

这需要在Linux和Solaris上都可以工作,我更愿意消除对shell的重复调用,并将整个内容保留在Perl中。


1
@hobbs:http://search.cpan.org/~durist/Proc-ProcessTable-0.45/ 看起来足够稳定。 - Hasturkun
@Hasturkun:我刚试了一下Proc::ProcessTable,结果被截断了 )-: - hippietrail
@hippietrail:截断怎么做?在哪个操作系统上? - Hasturkun
@Hasturkun:在Solaris上(因为这个问题被标记了)。我需要监视的进程是一个带有令人讨厌的长参数的perl脚本。根据我所读到的,Solaris对此信息的长度有一个硬限制,即使您直接使用procfs也是如此。 - hippietrail
@hippietrail:在这种情况下,我怀疑很难做到什么(尽管从struct psinfo中看到的,可能可以获取argv的地址,从进程内存中读取,但我真的不建议这样做)。 - Hasturkun
显示剩余2条评论
4个回答

1

快速而不太规范的方法(仅限UNIX):

my $user = (split /\s/,`who am i`)[0];

who am i 命令返回 TTY 的所有者 - 即您登录时的身份。

如果您想在纯 Perl 中执行此操作:

use POSIX;
my $tty = POSIX::ttyname(1); # The tty we are running in
my $uid = (stat $tty)[4];    # The owner uid of that tty
my $user = getpwuid($uid);   # The user with that uid

这将返回正确的用户,即使进行了多次su。这通常会使你(不那么有经验的)系统管理员感到恐慌。


0

我在调用mc脚本时意识到一个特殊情况(至少在我们的RHEL系统中),导致who am i命令没有输出任何内容。为了解决这个问题,我写了下面这个bash一行命令:

REALUSERNAME=$(ps uhp `ps -AjH | grep \`ps -u $USER fh | awk '{ print $0; if(index($0, "ps -u $USER fh")) exit 0;}' | tac | awk '{if(!index($0, "\\\\\_")){print $1; exit 0;}}'\` | awk '{print $3}'` | awk '{print $1}')

本质上,这个程序会倒序遍历 ps -u $USER fh 命令的输出结果,并截取最顶层的用户名列。

如果您有更好的想法或解决方案,欢迎分享 :-)


0

这是一个检查直接 setuid 更改的 Perl 程序:

#! /usr/bin/perl
sub callingUser() { my ($login, $pass, $uid, $gid) = getpwuid($<); return $login; }
sub effectiveUser() { my ($login, $pass, $uid, $gid) = getpwuid($>); return $login; } printf("真实用户名:%s\n", effectiveUser()); printf("调用用户名:%s\n", callingUser());

但是,由于您提到 setuid 更改可能在任何时候发生,您可能需要解析 ps 的输出:我会使用以下命令来执行。此命令仅使用 POSIX 中定义的功能,因此我希望它可移植到各种系统:

ps -e -o pid,ppid,user,ruser

0
也许以下是您想要的。函数hasBeenUser读取进程表,然后从当前进程向下跟踪进程链。如果沿途任何一个进程具有与所询问的用户名相等的userreal user字段,则该函数返回非零值。
#! /usr/bin/perl
# 判断进程是否被某个用户调用过 sub hasBeenUser($) { my ($username) = @_;
my $procs = {}; open(PS, "ps -e -o pid,ppid,user,ruser |") or die; while (defined(my $line = <PS>)) { next unless $line =~ m"^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+$"; my ($pid, $ppid, $user, $ruser) = (int($1), int($2), $3, $4); $procs->{$pid} = [$pid, $ppid, $user, $ruser]; } close(PS) or die;
my $pid = $$; while (exists($procs->{$pid})) { my $proc = $procs->{$pid}; delete $procs->{$pid}; # 不要冒着陷入无限循环的风险。 warn "D: checking process $pid\n"; if ($proc->[2] eq $username || $proc[3] eq $username) { warn "E: process $pid was called by $username.\n"; return 1; } last if $pid < 2; $pid = $proc->[1]; } return 0; }
hasBeenUser("del"); # 应该返回0 hasBeenUser("root"); # 应该返回非零值

有没有相同的Java等效版本? - Pintu
是的,使用Java也可以生成子进程并读取其输出。 - Roland Illig
请问您能否提供一些相关的示例? - Pintu
这段代码无法放在注释中。你可以提出一个新的问题,引用这个问题。但是这个想法只适用于POSIX系统,不适用于Windows系统。 - Roland Illig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接