#!/usr/local/bin/perl5 -T

$OSH = "/usr/local/bin/osh";

# Just in case we need to clear the IFS for the system call below.
$ENV{'IFS'} = '' if $ENV{'IFS'};
$ENV{'PATH'} = '/bin:/sbin';

# First we need to figure out which program it is.

if ($0 =~ /(mkdir|rmdir)/) {
  $prog = $1;
}
else {
  print "Invoked as incorrect program $1.\n";
  print "This script is used as a wrapper for mkdir and rmdir.\n";
  exit(1);
} 

# Any flags?
$mode = oct(700);
$recurse = 0;
$silent = 0;
while ($_ = $ARGV[0], /^-[psm]+$/) {
  $recurse = 1 if (/p/);
  if (/m/) {
    shift;
    if (($prog =~ /^mkdir$/) &&
        ($_ = $ARGV[0], /(^[0-7]{1,4}$)/)) {
      $mode = oct($1);
    } else {
      print "Improper command option.\n\n";
      print "Usage:\n\n\t$prog [-ps] dir\n\n" if ($prog =~ /^rmdir$/);
      print "Usage:\n\n\t$prog [-p] [-m absolute_mode] dir\n\n" if ($prog =~ /^mkdir$/);
      print "Wild cards and multiple directories are not allowed for security reasons.\n";
      print "As well, symlinks are not followed for $prog operations.\n";
      exit(1);
    }
  }
  $silent = 1 if ((/s/) && $prog =~ /^rmdir$/);
  shift;
}

if (($#ARGV != 0) || ($ARGV[0] =~ /^-/)) {
  print "Improper command option.\n\n";
  print "Usage:\n\n\t$prog [-ps] dir\n\n" if ($prog =~ /^rmdir$/);
  print "Usage:\n\n\t$prog [-p] [-m absolute_mode] dir\n\n" if ($prog =~ /^mkdir$/);
  print "Wild cards and multiple directories are not allowed for security reasons.\n";
  print "As well, symlinks are not followed for $prog operations.\n";
  exit(1);
}

# Get the directory.
if ($ARGV[0] =~ /\s*(.+)\s*/) {
  $dest = $1;
} else
  { print "huh?\n"; exit(1); }

# Check for someone trying to escape things out. It's facist, but better
# safe than sorry.
if ($dest =~ /["\\'`]/) {
  print "Special characters (ie. \", \\, ', `) are not allowed.\n";
  exit(1);
}

# Is directory a full path? If not, we need to make sure it is before the
# system call below. 
#if ($dest =~ /^[^\/]/) {
#  $cwd = `pwd`;
#  chop($cwd);
#  $dest = $cwd . "/" . $dest;
#}

# Get the user, which is the owner of the parent process since the
# current process was setuid(0) before spawning off.
#
# Btw, this is how `ps` gets the info for printing as well.
# By name.
#$USER=(getpwuid((stat("/proc/". getppid))[4]))[0];
# By UID.
$USER=(getpwuid((stat("/proc/". getppid))[4]))[2];

if ($pid = fork) {
  wait;
  $status = ($? >> 8);
  if ($status == 1) {
      umask 0;
      if ($recurse == 0) {
        die "Removal failed: $!\n" if (($prog =~ /^rmdir$/) && !(rmdir($dest)));
        die "Creation failed: $!\n" if (($prog =~ /^mkdir$/) && !(mkdir($dest,$mode)));
        exit (0);
      } else {
        if ($prog =~ /^mkdir$/) {
          @list = split('/',$dest);
          $next = shift(@list);
          $dest = $next;
          while (-e $dest) {
            $next = shift(@list);
            $dest = $dest . '/' . $next;
          }
          while (defined($next)) {
            die "Creation failed: $!\n" if (!(mkdir($dest,$mode)));
            $next = shift(@list);
            $dest = $dest . '/' . $next;
          }
          exit (0);
        } elsif ($prog =~ /^rmdir$/) {
          @list = split('/',$dest);
          $dest = join('/',@list);
          $done = 1;
          $pass = 0;
          while ((-e $dest) && ($done == 1)) {
            $done = rmdir($dest);
            if ($done == 1) {
              pop(@list);
              $pass += 1;
            }
            $dest = join('/',@list);
          }
          if (($dest ne "") && ($silent == 0)) {
            print "Non-empty directory found ($dest). Recursive rmdir stopped.\n";
            exit(1) if ($pass == 0);
          }
        }
      }
  } else {
    print "No permission to directory $dest\n";
    exit(1);
  }
} elsif (defined $pid) {

  # Ignore the interrupts until we get into the program.
  $SIG{'INT'} = 'IGNORE';
  $SIG{'QUIT'} = 'IGNORE';

  # Set the previously gotten UID.
  $> = $< = $USER;

  # Call osh test -w to see if they have priveledge to write where they
  # are trying to.
  exit (system("$OSH", "test", "-w \"$dest\"") >> 8);
} else {
  die "Can't fork: $!\n";
}
