Cisco-Conf
view release on metacpan or search on metacpan
lib/Cisco/Conf.pm view on Meta::CPAN
Example:
$self->Edit('emacs', 'myrouter.conf', '/tmp');
=cut
sub _System($$) {
my($class, $command) = @_;
$! = 0;
my $rc = system $command;
if ($rc == 0xff00) {
die "Command $command failed: " .
($! || "Unknown system error");
} elsif ($rc) {
die "Command $command exited, error status $rc";
}
}
sub _Edit ($$$$) {
my($self, $editor, $file, $tmpDir) = @_;
if ($< == $>) {
# We aren't running SUID, so things are easy.
return $self->_System(sprintf("%s %s", $editor, $file));
}
# Editing a file is a true security problem. :-(
# Most editors have escape sequences that allow to execute
# arbitrary shell commands with. When running suid root,
# this means that we can do just anything!
#
# We try to work around this problem as follows:
# First we create a copy of the file that should be
# edited. The real user becomes owner of this file.
#
# Next we fork a child. This child changes the EUID
# to the UID, so it is no longer running suid. Now
# we can edit the copy.
#
# Finally the copy is restored back to become the original.
# That's it, folks! :-)
#
my $configuration;
my $fh;
{
local $/ = undef;
$fh = IO::File->new($file, "r");
if (!$fh || !defined($configuration = $fh->getline()) ||
!$fh->close()) {
die "Error while reading $file: $!";
}
}
my $tmpFile = $tmpDir . "/cisconf.$$";
$fh = IO::File->new($tmpFile, "w");
if (!$fh || !chmod(0600, $tmpFile) ||
!chown($<, $(, $tmpFile) || !$fh->print($configuration) ||
!$fh->flush() || !$fh->close()) {
unlink $tmpFile;
die "Error while creating temporary file $tmpFile: $!";
}
my $pid = fork();
if (!defined($pid)) {
unlink $tmpFile;
die "Cannot fork: $!";
} elsif (!$pid) {
# This is the child; change UID and call the editor
$) = $(;
$> = $<;
exec sprintf("%s %s", $editor, $tmpFile);
}
{
local($SIG{'CHLD'}) = 'IGNORE';
wait;
if ($?) {
unlink $tmpFile;
die "Error while editing $tmpFile, error status was $?";
}
}
# Now copy the temporary file back
{
local $/ = undef;
$fh = IO::File->new($tmpFile, "r");
if (!$fh || !defined($configuration = $fh->getline()) ||
!$fh->close()) {
my $status = $!;
unlink $tmpFile;
die "Error while reading $tmpFile: $status";
}
}
unlink $tmpFile;
$fh = IO::File->new("$file.new", "w");
if (!$fh || !$fh->print($configuration) || !$fh->flush() ||
!$fh->close()) {
my $status = $!;
die "Error while creating new file $file.new: $status";
}
if (-f $file) {
unlink "$file.bak";
if (!rename $file, "$file.bak") {
die "Error while renaming $file to $file.bak: $!";
}
}
if (!rename "$file.new", $file) {
die "Error while renaming $file.new to $file: $!";
}
}
sub Edit ($$$$) {
my($self, $editor, $file, $tmpDir) = @_;
( run in 0.542 second using v1.01-cache-2.11-cpan-71847e10f99 )