#!/usr/bin/perl # # seced -- secure editor wrapper # Tom Christiansen # based on an idea by Ray Davis # # install suid root or with a suid wrapper %ok = ( '/usr/ucb/vi', 1, '/usr/ucb/ex', 1, '/bin/ed', 1, '/usr/convex/emacs', 1, '/usr/convex/edt', 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"; } }