#! /usr/bin/perl -w
# $Header: /global/src/usr.bin/src/RCS/runas.pl,v 1.2 2010/04/19 12:42:07 pb22 Exp $

# Use "pod2text" for info

=head1 NAME

runas - program to run daemons as non priviledge users

=head1 SYNOPSIS

B<runas> [B<-c> I<location>]  I<uid>  I<gid>  I<program> [I<args> ...]

=head1 DESCRIPTION

runas is equivalent to using su     but it strips off the environment and does not require the target user's shell to be legitimate (that is, listed under /etc/shells)

The main reason of using runas is to avoid having daemons run as the root user, in some cases this might be necessary (like login programs, such as ssh or telnetd that need to switch to the
user making the connection) but in many cases it might not be necessary at all.  It can be also a good replacement for su, since it prevents attacks to daemons through the use  of  environ-
ment variables. Just change (in your initialisation scripts under /etc/init.d) the line:

su - daemon -c /usr/bin/blah

to:

runas daemon daemongroup /usr/bin/blah

=head1 OPTIONS

This program just takes two options:

-?        Show summary of options.

-c        Chroot the daemon to a specific location.

=head1 SEE ALSO

chroot(2), chroot(8)

The TITAN FAQ (link to URL http://www.trouble.org/titan/FAQ.html)

=head1 AUTHOR

This  manual page was written by Javier Fernandez-Sanguino Pen~a <jfs@computer.org> for the Debian system (but may be used by others).  Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation.

On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL.

=cut


use Getopt::Long;
Getopt::Long::Configure ("require_order");
# abuse bundling_override to allow -W and -w as different
# use Getopt::Long qw(:config require_order bundling_override);
use Pod::Usage;
%opts = (
	"help|h"	=> \$help,
	"verbose|v"	=> \$verbose,
	"chroot|c:s"	=> \$chroot,
);

GetOptions (%opts) || pod2usage();
pod2usage(-verbose => 2) if $help;
pod2usage() unless $#ARGV > 1;

$uid = shift;
$gid = shift;

# if not numeric, try to map to a number
unless ($uid =~ /^\d+$/) {
	my($ouid) = $uid;
	$uid=(getpwnam($uid));
	die("$0: unknown user '$ouid'\n") unless defined $uid;
}	
unless ($gid =~ /^\d+$/) {
	my($ogid) = $gid;
	$gid=(getgrnam($gid));
	die("$0: unknown group '$ogid'\n") unless defined $gid;
}	

# chroot as requested
if ($chroot) {
	print STDERR "# $0: chroot to $chroot\n" if $verbose;
	chdir($chroot) || die("$0: failed to chdir($chroot): $!\n");
	chroot(".") || die("$0: failed chroot($chroot): $!\n");
}
	
$( = $gid || die("$0: failed to set gid $gid: $!\n") unless $( == $gid;
$< = $uid || die("$0: failed to set uid $uid: $!\n") unless $< == $uid;

print STDERR "# $0: run '@ARGV' as $uid:$gid\n" if $verbose;
exec @ARGV;

die("$0: exec '@ARGV' failed: $!\n");
