/ag-update-shadow
#!/usr/bin/perl
use strict;

use AwesomeGrid;
use AwesomeGrid::Config;
use AwesomeGrid::User;

my $etc = '/etc';	# In production, this should be '/etc'

my $config = AwesomeGrid::Config::config();

# Get a list of awesomegrid users
opendir USERS, "$AwesomeGrid::confdir/users";
my @agusers = grep {/^[^.]/} readdir USERS;
close USERS;

# Get a list of system users
my @sysusers;
my @allsysusers;

open PASSWD, "$etc/passwd";
while (<PASSWD>) {
	my ($username, undef, $uid, $gid, $gecos, $home, $shell) = split(/:/);
	push(@allsysusers, $username);
	next unless $gecos =~ /^\[AG\]/;	# Skip non-AG-managed users
	push(@sysusers, $username);
}
close PASSWD;

# Check to see what there is in /etc/passwd that should be removed.
my @deletes;
for my $sysuser (@sysusers) {
	unless (grep { $_ eq $sysuser } @agusers) {
		push(@deletes, $sysuser);
	}
}

# Check to see which users are going to be added
my @adds;
for my $aguser (@agusers) {
	unless (grep { $_ eq $aguser } @allsysusers) {
		push(@adds, $aguser);
	}
}

# Check to see which users should be updated
my @updates;
for my $user (@allsysusers) {
	if (grep { $_ eq $user } @agusers) {
		push(@updates, $user);
	}
}

unless (@adds or @deletes or @updates) {
	print "Nothing to do.\n";
	exit 0;
}

print "Adding: ",join(' ',@adds),"\n" if @adds;
print "Deleting: ",join(' ',@deletes),"\n" if @deletes;
print "Updating: ",join(' ',@updates),"\n" if @updates;

print "Proceed? [y/N] ";
my $ans = <STDIN>;
unless ($ans =~ /^[Yy]$/) {
	exit(0);
}

# Before proceeding, make a backup copy of /etc/passwd and /etc/shadow
system("cp $etc/passwd $etc/passwd.ag_backup");
system("cp $etc/shadow $etc/shadow.ag_backup");

# Note that parsing /etc/passwd and /etc/shadow like this is pretty bad
# form, but it's the only way I can test it without being root. It's
# also the only way I can dump the hash directly into /etc/shadow.

# Deletes first
if (@deletes or @updates) {
	open PASSWD, "$etc/passwd";
	open PASSWDOUT, ">$etc/passwd.out";
	while (<PASSWD>) {
		my ($username) = split(/:/);
		next if grep { $username eq $_ } (@deletes,@updates);
		print PASSWDOUT;
	}
	close PASSWDOUT;
	close PASSWD;

	open SHADOW, "$etc/shadow";
	open SHADOWOUT, ">$etc/shadow.out";
	while (<SHADOW>) {
		my ($username) = split(/:/);
		next if grep { $username eq $_ } (@deletes,@updates);
		print SHADOWOUT;
	}
	close SHADOWOUT;
	close SHADOW;

	rename "$etc/passwd.out","$etc/passwd";
	chmod 0644, "$etc/passwd";
	rename "$etc/shadow.out","$etc/shadow";
	chmod 0640, "$etc/shadow";
	system(qq{chown root.shadow "$etc/shadow"});
}

# Then add new ones.
if (@adds or @updates) {
	# Perhaps appending directly is a bad idea...
	open PASSWD, ">>$etc/passwd";
	open SHADOW, ">>$etc/shadow";

	for my $add (@updates,@adds) {
		my $agu = AwesomeGrid::User->load($add);
		printf PASSWD "%s:x:%d:%d:[AG]:%s:%s\n", $agu->{username},
				$agu->{uid}, $agu->{uid},
				"$config->{homedir}/$agu->{username}",
				$config->{'default-shell'};
		printf SHADOW "%s:%s:%d:%d:%d:%d:::\n",
				$agu->{username},
				$agu->{'passwd-unix-md5'},
				time / 86400, 0, 99999, 7;
		unless (-d "$config->{homedir}/$agu->{username}") {
			print "Creating homedir for $agu->{username}\n";
			mkdir "$config->{homedir}/$agu->{username}";
			chown $agu->{uid}, $agu->{uid},
				"$config->{homedir}/$agu->{username}";
		}
	}
	close PASSWD;
	close SHADOW;
}