#!/usr/bin/perl
#use Mooix::Thing;
run sub {
	my $this=shift;
	%_=@_;
	my $id = $_{id};
	delete $_{id};
	my $owner = $_{owner};
	delete $_{owner};

	# Make sure that the end of the id is something sane. It has to
	# serve as a perl field in method runs, so can't have various
	# punctuation.
	my ($baseid)=$id;
	$baseid=~s/.*\///;
	if (! length $baseid || $baseid !~ /[._a-zA-Z0-9][_a-zA-Z0-9]*/) {
		$this->usage("bad id");
	}
	
	# Basic object setup. Make the directory. If the perms are not 777,
	# we won't be able to access it after, since it will probably not
	# be accessable to all on our caller stack.
	if (! -d $id) {
		my $oldmask = umask(0);
		mkdir($id, 0777) or $this->croak("mkdir $id");
		umask($oldmask);
	}
	
	# Set parent link up before it's a mooix object. We can't do it
	# after (w/o bypassing libmooproxy..), and we must be the parent to
	# get the ability to modify it in arbitrary ways.
	symlink($this->id, "$id/parent") or $this->croak("symlink parent");
	# Also set up the owner link now.
	symlink($owner->id, "$id/owner") or $this->croak("symlink owner")
		if ($owner);
	
	# Note that this file creation happens before the directory is an
	# object, so it will not be proxied through to mood. So, the 
	# .mooix file will come out owned by whatever sandbox user mood 
	# uses. Have to fix this below.
	open(OUT, ">", "$id/.mooix") or $this->croak("write .mooix");
	close OUT;
	# Now mood knows that the directory is a mooix object, and it knows
	# that this object is its parent.
	
	# Fix up perms to limit access. This can only be done from a method
	# running as the new child object, not from this method. So, launch
	# such a method!
	my $child = Mooix::Thing->get($id);
	$child->newhelper;
	# We can't trust that that did the right thing; an attacker could
	# have played games with the parent link and caused some other
	# program to run. So, check its result.
	my @stat=stat($id) or $this->croak("stat $id");
	if (($stat[2] & 07777) != 0755) {
		$this->croak("directory perms are wrong!");
	}

	# In the window when the directory was mode 777, anyone could have
	# put files or directories in it. That could be bad, so we will scan
	# through it and attempt to find such things. Since someone trying
	# to do that is an attack, we will whine bitterly, and abort.
	# TODO does just giving up here make it too easy to DOS the moo?
	opendir(DIR, $id) or $this->croak("opendir");
	while (defined ($_ = readdir(DIR))) {
		next if $_ eq '.' or $_ eq '..' or $_ eq '.mooix' or $_ eq 'parent';
		next if $_ eq 'owner' && $owner;
		$this->croak("Someone made a file named '$_' in $id during object creation. Not trying to recover; giving up. Inform a moo admin of this attempt to hack the moo!");
	}
	# Also, an attacker could have messed with the .mooix file, so
	# check to make sure that it is owned by the same user as
	# the directory. Groups can vary.
	my @dirstat=stat($id) or $this->croak("stat $id");
	my @mooixstat=stat("$id/.mooix") or $this->croak("stat $id/.mooix");
	if ($dirstat[4] != $mooixstat[4]) {
		$this->croak("$id/.mooix is not owned by right user ($dirstat[4] vs $mooixstat[4]). Is someone trying something sneaky?");
	}
	# And an attacker could have screwed with the parent link, so check
	# that it points to the right place.
	if (readlink("$id/parent") ne $this->id) {
		$this->croak("$id/parent does not point to ".$this->id.". Is someone trying something sneaky?");
	}
	# And an attacker could have messed with the owner link.
	if ($owner && readlink("$id/owner") ne $owner->id) {
		$this->croak("$id/owner does not point to ".$owner->id.". Is someone trying something sneaky?");
	}

	# Now we have an working object. Initialize it, and return it.
	# Note use of @_ -- some objects have odd parameter lists.
	return $child if $_{noinit};
	return $child->init(@_);
}
