#!/usr/bin/perl
use strict;
use File::Temp qw/ :POSIX /;

# signup-scripts-backend
# Copyright (C) 2006  Jeff Arnold <jbarnold@mit.edu>
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
# 
# See /COPYRIGHT in this repository for more information.

$ENV{PATH} = '';

my $username = $ARGV[0];

# Complain unless submitted username contains only valid characters
complain("bad username") unless($username =~ /^[\w._-]+$/);

open BANNEDUSERS, "</afs/athena.mit.edu/contrib/scripts/admin/users.banned" or
    complain("internal error");
while (<BANNEDUSERS>) {
    chomp;
    complain("banned username") if (lc eq lc $username);
}
close(BANNEDUSERS);

my %filsys;
open HESINFO, '-|', '@hesinfo_path@', '--', $username, 'filsys' or
    complain("internal error");
while (<HESINFO>) {
	chomp;
	my %f; @f{qw(type path rw mount order)} = split / /;
	%filsys = %f if (($f{order} || 9999) <= ($filsys{order} || 9999));
}
close HESINFO;
unless (%filsys &&
	$filsys{type} eq 'AFS' &&
	$filsys{path} =~ /^\/afs\/[\w\._\/-]+/ &&
	$filsys{mount} eq "/mit/$username") {
	complain("athena user not found");
}
my $homedir = $filsys{path};

# Tell AFS that we don't want to trigger fakestat, and confirm user's homedir
chdir $homedir or complain("athena homedir not found");
opendir TEMP, '.';
closedir TEMP;

# Obtain user's homedir uid
my (undef, undef, undef, undef, $uid1, $gid1, undef, undef, undef, undef, undef, undef, undef) = stat '.' or complain("athena homedir could not be examined");

# Complain if user's uid is too low or too high
complain("bad uid") unless($uid1 > 110 and $uid1 < (1 << 31));

# Complain if user's .scripts-signup file does not exist
#complain("scripts-signup file not found") unless(-e '.scripts-signup');

# Complain if the user's username is already taken
complain("username already taken") if(getpwnam $username);

# Complain if user's uid is already taken
complain("uid already taken") if(getpwuid $uid1);

if($homedir !~ /\/afs\/athena\.mit\.edu\/user\//) {
	$gid1 = $uid1;
}

# Complain if user's gid is already taken
complain("gid already taken") if(getgrgid $gid1);

my $disabledmsg = "scripts.mit.edu signups are currently disabled";
if(-e "/afs/athena.mit.edu/contrib/scripts/admin/nosignup") {
	open NOSIGNUP, "</afs/athena.mit.edu/contrib/scripts/admin/nosignup" or
		complain("internal error");
	while (<NOSIGNUP>) {
		chomp;
		$disabledmsg .= "\n$_";
	}
	close NOSIGNUP;
	complain($disabledmsg);
}
elsif(-e "/etc/nosignup") {
	$disabledmsg .= " on this server";
	open NOSIGNUP, "</etc/nosignup" or complain("internal error");
	while (<NOSIGNUP>) {
		chomp;
		$disabledmsg .= "\n$_";
	}
	close NOSIGNUP;
	complain($disabledmsg);
}

# Get credentials
my $ccache = tmpnam();
$ENV{'KRB5CCNAME'} = $ccache;
my $exit_status = system("/usr/bin/kinit", "-k", "-t", "/etc/signup.keytab", "daemon/scripts-signup.mit.edu");
if (($exit_status >> 8) != 0) {
    die "Couldn't get Kerberos credentials for account creation!";
}
my $pid;
my @ldap_servers = ('doppelganger', 'alter-ego', 'body-double');
my $selected_server = $ldap_servers[int(rand(3))];
defined ($pid = open LDAP, '|-') or complain("internal error");
if (!$pid) {
	close STDOUT;
	open STDOUT, '>/dev/null';
	exec '@ldapadd_path@', '-c', '-Y', 'gssapi', '-H', "ldap://$selected_server.mit.edu";
	exit 1;
}
print LDAP <<EOF;
dn: uid=$username,ou=People,dc=scripts,dc=mit,dc=edu
objectClass: posixAccount
cn: $username
uid: $username
uidNumber: $uid1
gidNumber: $gid1
homeDirectory: $homedir
loginShell: /usr/local/bin/mbash

dn: cn=$username,ou=Groups,dc=scripts,dc=mit,dc=edu
objectClass: posixGroup
cn: $username
gidNumber: $gid1

dn: apacheServerName=$username.scripts.mit.edu,ou=VirtualHosts,dc=scripts,dc=mit,dc=edu
objectClass: apacheConfig
apacheServerName: $username.scripts.mit.edu
apacheServerAlias: $username.scripts
apacheDocumentRoot: $homedir/web_scripts
apacheSuexecUid: $uid1
apacheSuexecGid: $gid1

dn: scriptsVhostName=$username.scripts.mit.edu,ou=VirtualHosts,dc=scripts,dc=mit,dc=edu
objectClass: scriptsVhost
scriptsVhostName: $username.scripts.mit.edu
scriptsVhostAlias: $username.scripts
scriptsVhostAccount: uid=$username,ou=People,dc=scripts,dc=mit,dc=edu
scriptsVhostDirectory: .

EOF
close LDAP or complain("internal error");
# Add disk quota for user
#system('@sudo_path@', '-u', 'root', '/usr/sbin/setquota', $username, '0', '25000', '0', '10000', '-a');

system("kdestroy");

printexit("done", 0);

sub complain {
  my ($complaint) = @_;
  printexit($complaint, 1);
}

sub printexit {
  my ($msg, $status) = @_;
  print $msg;
  exit($status);
}
