Subject: Re: rvi - restricted vi??
From: Tom Christiansen <[email-masked]>
Date: Wed, 1 Sep 1993 15:55:12 GMT
Newsgroups: comp.unix.questions,comp.unix.admin,comp.unix.shell

From the keyboard of [email-masked] (Cindy Wang):
:I know someone who is setting up restricted shell.  He'd like
:to have vi in /usr/rbin but couldn't because of the :!shell feature 
:in vi.  Is there a rvi -- restricted vi somewhere?

I've used this, which is a wrapper around any editor.  

--tom

#!/usr/bin/perl
#
# seced  -- secure editor wrapper
# Tom Christiansen <[email-masked]>
# based on an idea by Ray Davis <[email-masked]>
#
# install suid root or with a suid wrapper

%ok = ( '/usr/ucb/vi',		1,
	'/usr/ucb/ex',		1,
	'/bin/ed',		1,
	'/usr/local/bin/emacs',	1,
      );

$tmpdir = "/tmp/seced.$$";

die "$0: Not superuser\n" if $>;
die "usage: $0 file ...\n" if $#ARGV < 0;

chop($cwd = `pwd`);

mkdir($tmpdir,0700) || die "can't mkdir $tmpdir: $!";
chdir($tmpdir) 	    || die "can't chdir $tmpdir: $!";
mkdir('tmp',  0777) || die "can't mkdir $tmpdir/tmp: $!";

&cp_editor;
&cp_files;

if ($kid = fork) {
    die "cannot fork: $!" 	if $kid == -1;
    $pid = wait until $pid == $kid || $pid == -1;
    die "wait: no kids" 	if $pid == -1;
    warn "$0: edit failed with status " . ($? >> 8) . "\n"
	if $?;
} else { 
    chroot($tmpdir) || die "can't chroot $tmpdir: $!";
    exec($editor, @ARGV);
    # NOT REACHED
} 

&replace_files unless $?;

chdir('/') 	   || die "absurd failure to chdir to /: $!";

exec('/bin/rm', '-rf', $tmpdir);

# NOT REACHED

sub cp_editor {
    $editor =  $ENV{'SECED'} 
	    || $ENV{'VISUAL'} 
	    || $ENV{'EDITOR'} 
	    || '/usr/ucb/vi';

    die "$0: need full path for \$EDITOR: $editor\n" 
	unless $editor =~ m#^/#;

    die "$0: illegal \$EDITOR: $editor\n" 
	unless defined $ok{$editor};

    system('/bin/cp', $editor, '.') 
	&& die "$0: couldn't cp editor\n";

    if ($editor eq '/usr/ucb/vi' || $editor eq '/usr/ucb/ex') {
	$home = $ENV{'HOME'} || '/';
	$startup = "$home/.exrc";
	if (-e $startup && -O _) {
	    system('/bin/cp', $startup, '.') 
		&& die "$0: couldn't cp $startup\n";
	    chown($<, -1, '.exrc');
	} 
    } 

    $editor =~ s#.*(/[^/]+)$#.$1#;
} 

sub cp_files {
    @files = grep(/^[^-]/, @ARGV);
    grep(s#^[^/]#$cwd/$&#, @files);

    die "no files to edit" if $#files < 0;

    system('/bin/cp', @files, '.') 
	&& die "couldn't cp files";

    chown($<, -1, <*>)
	|| die "couldn't chown files to uid $<";

    for (@files) { 
	($local = $_) =~ s#.*/##;
	unless (-T) {
	    warn "$0: WARNING: $_ not a text file\n";
	    sleep(1);
	}
	$mtime{$_} = (stat($local))[9];
    }
} 

sub replace_files {
    for (@files) {
	($local = $_) =~ s#.*/##;
	if ((stat($local))[9] == $mtime{$_}) {
	    warn "$0: $_ unmodified\n";
	    next;
	} 
	system('/bin/cp', $local, $_)
	    && die "$0: can't cp $local $_\n";
    } 
} 
-- 
    Tom Christiansen      [email-masked]       303-444-3212