Skip to content

Instantly share code, notes, and snippets.

@fumiyas
Created August 8, 2013 04:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fumiyas/6181427 to your computer and use it in GitHub Desktop.
Save fumiyas/6181427 to your computer and use it in GitHub Desktop.
runuser(1) clone to emulate Red Hat Linux
#!/usr/bin/perl
##
## runuser(1) clone to emulate Red Hat Linux
## Copyright (c) 2008-2009 SATOH Fumiyasu @ OSS Technology Corp.
## <http://www.osstech.co.jp>
##
## License: GNU General Public License version 2 or later
## Date: 2009-03-12, since 2008-06-13
##
use strict;
use warnings;
use English qw(-no_match_vars);
use Getopt::Long;
use constant true => 1;
use constant false => undef;
sub pinfo {
chomp(my $m = join('', @_));
print STDERR "$0: INFO: $m\n";
}
sub pwarn {
chomp(my $m = join('', @_));
print STDERR "$0: WARNING: $m\n";
}
sub perr {
chomp(my $m = join('', @_));
print STDERR "$0: ERROR: $m\n";
}
sub pdie {
perr(@_);
exit(1);
}
my $group = undef;
my $shell = undef;
my $login_shell_f = false;
my $preserve_env_f = false;
my $not_implemented = sub { pdie "$_[0] option not implemented"; };
my $cmd_usage = "Usage: $0 [OPTIONS] [-] [USER [ARG] ...]";
{
## Trap warning messages from Getopt::Long
local($SIG{'__WARN__'}) = sub {
my ($msg) = shift(@_);
pwarn $msg;
};
## I don't like default behavior.
Getopt::Long::Configure('bundling');
Getopt::Long::Configure('no_ignore_case');
Getopt::Long::Configure('no_auto_abbrev');
GetOptions(
'l|login' => \$login_shell_f,
'g|group=s' => \$group,
'G|groups=s' => $not_implemented,
'c|command=s' => $not_implemented,
'f|fast' => $not_implemented,
'm|p|preserve-environment' =>\$preserve_env_f,
's|shell=s' => \$shell,
) || exit(1);
}
my $login = @ARGV ? shift(@ARGV) : 'root';
my @argv = @ARGV;
my @pwent = getpwnam($login);
@pwent || pdie "User does not exist: $login";
my $uid = $pwent[2];
my $gid = defined($group) ? getgrnam($group) : $pwent[3];
defined($gid) || pdie "Group does not exist: $group";
defined($shell) || ($shell = $pwent[8] || '/bin/sh');
my $argv0 = $shell;
$argv0 =~ s#.*/#-# if ($login_shell_f);
unless ($preserve_env_f) {
for my $env_name (keys %ENV) {
next if ($env_name =~ /^(LANG|LC_\w+|PATH)$/);
delete($ENV{$env_name});
}
$ENV{'LOGNAME'} = $ENV{'USER'} = $login;
$ENV{'HOME'} = $pwent[7];
$ENV{'SHELL'} = $shell;
}
$EGID = "$gid $gid";
$ERRNO && pdie "Cannot change effective GID: $gid: $!";
$GID = $gid;
$ERRNO && pdie "Cannot change real GID: $gid: $!";
$EUID = $uid;
$ERRNO && pdie "Cannot change effective UID: $uid: $!";
$UID = $uid;
$ERRNO && pdie "Cannot change real UID: $uid: $!";
unless (exec {$shell} $argv0, @argv) {
pdie "Cannot execute command: $shell: $!";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment