Index: /server/common/oursrc/accountadm/Makefile.in
===================================================================
--- /server/common/oursrc/accountadm/Makefile.in	(revision 58)
+++ /server/common/oursrc/accountadm/Makefile.in	(revision 58)
@@ -0,0 +1,11 @@
+CC = @CC@
+CFLAGS = @CFLAGS@
+prefix = @prefix@
+
+all-local: signup-scripts-frontend
+
+signup-scripts-frontend:
+	$(CC) $(CFLAGS) -o $@ signup-scripts-frontend.c	
+
+clean:
+	rm -f signup-scripts-frontend
Index: /server/common/oursrc/accountadm/admof.in
===================================================================
--- /server/common/oursrc/accountadm/admof.in	(revision 58)
+++ /server/common/oursrc/accountadm/admof.in	(revision 58)
@@ -0,0 +1,98 @@
+#!/usr/bin/perl
+use strict;
+
+# admof
+# 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 $targetuser;
+unless(($targetuser) = ($ARGV[0] =~ /^([\w._-]+)$/)) {
+  error("Invalid locker name: <$ARGV[0]>.");
+}
+my $curuser;
+unless(($curuser) = ($ARGV[1] =~ /^([\w._-]+)\@ATHENA\.MIT\.EDU$/)) {
+  error("An internal error has occurred.\nContact scripts\@mit.edu for assistance.");
+}
+
+my $fs = `@fs_path@ 2>/dev/null la /mit/$targetuser/`;
+my @fs = split(/\n/, $fs);
+
+#Access list for . is
+#Normal rights:
+#  system:scripts-root rlidwka
+#  system:anyuser rl
+
+unless($fs[0] =~ /^Access list for \/mit\/$targetuser\/ is$/ &&
+       $fs[1] =~ /^Normal rights:$/) {
+  error("Cannot find locker <$targetuser>.");
+}
+
+if($ARGV[2] && !getpwnam($targetuser)) {
+  error("Locker <$targetuser> does not have a scripts.mit.edu account.");
+}
+
+for(my $i = 2; $i < @fs; $i++) {
+  my ($id) = ($fs[$i] =~ /^  ([\w:_-]+) rlidwka$/);
+  if($id eq "") { next; }
+  my $group;
+  if($id eq $curuser) { success(); }
+  elsif(($group) = ($id =~ /^(system:.+)/)) {
+    my $mems = `@pts_path@ 2>/dev/null membership $group`;
+    my @mems = split(/\n/, $mems);
+
+#Members of system:scripts-root (id: -56104) are:
+#  hartmans
+#  jbarnold
+#  presbrey
+#  tabbott
+#  hartmans.root
+
+    next if($mems[0] !~ /^Members of $group \(id: \S+\) are:$/);
+    
+    if($mems =~ /\s+\Q$curuser\E\s+/) {
+	success();
+    }
+  }
+}
+
+print <<END;
+
+ERROR:
+It appears as though you are not an administrator of locker <$targetuser>.
+In order to be able to su to <$targetuser>, you must have full AFS access
+to the root directory of locker <$targetuser>.  Try running the command
+fs sa /mit/$targetuser $curuser all
+on Athena in order to explicitly grant yourself full AFS access.
+Contact scripts\@mit.edu if you are unable to solve the problem.
+
+END
+
+exit(1);
+
+sub error {
+  print STDERR "\nERROR:\n$_[0]\n\n";
+  exit(1);
+}
+
+sub success {
+  print STDERR "\n== SUCCESS ==\nYou are now logged in as user <$targetuser>.\n";
+  print STDERR "To return to being <$curuser>, type \"exit\".\n\n";
+  exit(33);
+}
Index: /server/common/oursrc/accountadm/configure.in
===================================================================
--- /server/common/oursrc/accountadm/configure.in	(revision 58)
+++ /server/common/oursrc/accountadm/configure.in	(revision 58)
@@ -0,0 +1,52 @@
+AC_INIT(signup-scripts-frontend.c)
+
+AC_PROG_CC
+
+AC_DEFUN(REQUIRE_PATH,[
+AC_SUBST($1_path)
+if test "[$]$1_path" = ""; then
+        AC_ERROR(Cannot find $1)
+fi
+])
+
+AC_DEFUN(LOCATE,[
+AC_PATH_PROG($1_path, $1)
+REQUIRE_PATH($1)
+])
+
+dnl Needed by admof.in
+
+AC_ARG_WITH(fs,
+[  --with-fs[=PATH]          fs is located at PATH],[
+  if test "$withval" != "no" -a "$withval" != "yes"; then
+    fs_path="$withval"
+  fi
+])
+REQUIRE_PATH(fs)
+
+AC_ARG_WITH(pts,
+[  --with-pts[=PATH]         pts is located at PATH],[
+  if test "$withval" != "no" -a "$withval" != "yes"; then
+    pts_path="$withval"
+  fi
+])
+REQUIRE_PATH(pts)
+
+dnl Needed by signup-scripts-backend.in
+
+LOCATE(ls)
+LOCATE(grep)
+LOCATE(sudo)
+LOCATE(useradd)
+LOCATE(groupadd)
+LOCATE(setquota)
+LOCATE(hesinfo)
+
+dnl Needed by modbash.in
+
+LOCATE(bash)
+
+AC_OUTPUT(Makefile)
+AC_OUTPUT(admof)
+AC_OUTPUT(signup-scripts-backend)
+AC_OUTPUT(modbash)
Index: /server/common/oursrc/accountadm/modbash.in
===================================================================
--- /server/common/oursrc/accountadm/modbash.in	(revision 58)
+++ /server/common/oursrc/accountadm/modbash.in	(revision 58)
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+@bash_path@ --rcfile /usr/local/etc/modbashrc "$@"
Index: /server/common/oursrc/accountadm/modbashrc
===================================================================
--- /server/common/oursrc/accountadm/modbashrc	(revision 58)
+++ /server/common/oursrc/accountadm/modbashrc	(revision 58)
@@ -0,0 +1,35 @@
+# System-wide .bashrc file for interactive bash(1) shells.
+
+. /etc/bashrc
+
+shopt -s checkwinsize
+
+# enable bash completion in interactive shells
+
+#if [ "$PS1" -a -f /etc/bash_completion ]; then
+#    . /etc/bash_completion
+#fi
+# ~/.bashrc: executed by bash(1) for non-login shells.
+
+export PS1='[\u@scripts]:\w\$ '
+umask 022
+
+# You may uncomment the following lines if you want `ls' to be colorized:
+# export LS_OPTIONS='--color=auto'
+# eval `dircolors`
+# alias ls='ls $LS_OPTIONS'
+# alias ll='ls $LS_OPTIONS -l'
+# alias l='ls $LS_OPTIONS -lA'
+#
+# Some more alias to avoid making mistakes:
+# alias rm='rm -i'
+# alias cp='cp -i'
+# alias mv='mv -i'
+
+if [ -f /mit/$USER/.bashrc.scripts ]; then
+	. /mit/$USER/.bashrc.scripts
+fi
+
+if [ -d ~/web_scripts ]; then
+	cd ~/web_scripts
+fi
Index: /server/common/oursrc/accountadm/mrproper
===================================================================
--- /server/common/oursrc/accountadm/mrproper	(revision 58)
+++ /server/common/oursrc/accountadm/mrproper	(revision 58)
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+rm -f signup-scripts-frontend admof signup-scripts-backend
+rm -f configure config.* Makefile
+rm -rf auto*.cache
Index: /server/common/oursrc/accountadm/signup-scripts-backend.in
===================================================================
--- /server/common/oursrc/accountadm/signup-scripts-backend.in	(revision 58)
+++ /server/common/oursrc/accountadm/signup-scripts-backend.in	(revision 58)
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+use strict;
+
+# 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._-]+$/);
+
+complain("banned username") if(`@grep_path@ '$username' /afs/athena.mit.edu/contrib/scripts/admin/users.banned` != "");
+
+my $homedir;
+my $filsys = `@hesinfo_path@ $username filsys`;
+# AFS /afs/athena.mit.edu/user/j/b/jbarnold w /mit/jbarnold
+if($filsys =~ /^AFS\s(\/afs\/[\w\._\/-]+)\s.*\s\/mit\/$username$/) {
+	$homedir = $1;
+}
+else {
+	complain("athena user not found");
+}
+
+# Run ls to confirm user's homedir and obtain user's homedir uid
+my $ls_regexp = '^\S*\s+\S*\s+(\S*)\s+(\S*)\s+\S*\s+\S*\s+\S*\s+\S*\s+(\S*).*$';
+my ($uid1, $gid1, $name1) = (`@ls_path@ -dln '$homedir'` =~ $ls_regexp);
+
+# Complain if user's homedir does not exist
+complain("athena homedir not found") unless($name1 eq $homedir);
+
+# Complain if user's uid is too low or too high
+complain("bad uid") unless($uid1 > 110 and $uid1 < (1 << 31));
+
+# Run ls to confirm user's .scripts-signup file
+my ($uid2, $gid2, $name2) = (`@ls_path@ -dln '$homedir/.scripts-signup'` =~ $ls_regexp);
+
+# Complain if user's .scripts-signup file does not exist
+#complain("scripts-signup file not found") unless($name2 eq "$homedir/.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);
+
+# Add user to /etc/passwd
+`@sudo_path@ -u root @groupadd_path@ -g '$gid1' '$username'`;
+`@sudo_path@ -u root @useradd_path@ -d '$homedir' -s '/usr/local/bin/modbash' -u '$uid1' -g '$gid1' -G users '$username'`;
+# Add disk quota for user
+`@sudo_path@ -u root @setquota_path@ '$username' 0 25000 0 10000 -a`;
+
+printexit("done", 0);
+
+sub complain {
+  my ($complaint) = @_;
+  printexit($complaint, 1);
+}
+
+sub printexit {
+  my ($msg, $status) = @_;
+  print $msg;
+  exit($status);
+}
Index: /server/common/oursrc/accountadm/signup-scripts-frontend.c
===================================================================
--- /server/common/oursrc/accountadm/signup-scripts-frontend.c	(revision 58)
+++ /server/common/oursrc/accountadm/signup-scripts-frontend.c	(revision 58)
@@ -0,0 +1,48 @@
+/*
+ * signup-scripts-frontend
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern char **environ;
+
+int main(int argc, char **argv) {
+	environ=NULL;
+	if(argc != 2) {
+		exit(1);
+	}
+
+	char uid[21]; // 64-bit uid requires 21
+	int retval = snprintf(uid, 21, "%d", getuid());
+	if(retval < 0 || retval >= 21) {
+		exit(1);
+	}
+	if(setreuid(geteuid(), -1) != 0) {
+		exit(1);
+	}
+	char *v[3];
+#define BACKEND_PATH "/usr/local/sbin/signup-scripts-backend"
+	v[0] = BACKEND_PATH;
+	v[1] = argv[1];
+	v[2] = NULL;
+	execv(BACKEND_PATH, v);
+	return 1;
+}
Index: /server/fedora/Makefile
===================================================================
--- /server/fedora/Makefile	(revision 57)
+++ /server/fedora/Makefile	(revision 58)
@@ -20,5 +20,5 @@
 
 upstream	= openafs krb5 httpd
-oursrc		= execsys tokensys lockeradm sqladm httpdmods
+oursrc		= execsys tokensys accountadm sqladm httpdmods
 allsrc		= $(upstream) $(oursrc)
 oursrcdir	= ${PWD}/../common/oursrc
