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 )