#!/usr/bin/perl

# niscript.pl by Gerben Wierda <gerben_wierda@rna.nl>

# This little script is an adaptation of the original niscript sh script by
# Joe Block <jpb@creol.ucf.edu>
# instead of using fixed uid/gid and thus not robust if you run it on a
# system where groups and/or users have been added, this script checks
# if the users/groups are there and if not creates them with free id's.

print <<_WARNING

This script massages your netinfo database.  This can severely break
your system.  If your netinfo database breaks, you get to keep the parts.

No Warranty. Really.

This script tries to create two groups (if they do not already exist):
- postfix
- maildrop
and tries to create a user (if it does not already exist)
- postfix
which is member of group postfix.

_WARNING
;

# The script starts to look at id 88 (both for user and group) and up to 65535
# It dies if no free id is found.

my $postfixgid = undef;
my $maildropgid = undef;
my $postfixuid = undef;

# First create

my @groups = readgroups();
foreach $group (@groups) {
	(my $groupname, undef, my $gid, undef) = split( ':', $group);
	if ($groupname eq 'postfix') {
		warn "You already have a postfix group (with gid $gid)\n";
		$postfixgid = $gid;
	}
	if ($groupname eq 'maildrop') {
		warn "You already have a maildrop group (with gid $gid)\n";
		$maildropgid = $gid;
	}
}

if (not defined $postfixgid) {
	$postfixgid = creategroup( 'postfix');
}

if (not defined $maildropgid) {
	$maildropgid = creategroup( 'maildrop');
}

my @users = readusers();
foreach $user (@users) {
	(my $username, undef, my $uid, undef) = split( ':', $user);
	if ($username eq 'postfix') {
		warn "You already have a postfix user (with uid $uid)\n";
		$postfixuid = $uid;
	}
}

if (not defined $postfixuid) {
	$postfixuid = createuser( 'postfix', '"Postfix User"',
				  '/usr/bin/false', '/etc/postfix',
				  $postfixgid);
	addusertogroup( 'postfix', 'postfix');
}

warn "\n";

sub creategroup
{
	my $name = shift;
	open( NIDUMP, "nidump group /|") or die "Cannot run nidump\n";
	my @groups=<NIDUMP>;
	close( NIDUMP);

	my $tryno;
	NEXTNO: for ($tryno = 88; $tryno <= 65535; $tryno++) {
		foreach my $group (@groups) {
			(my $groupname, undef, my $gid, undef) =
				split( ':', $group);
			next NEXTNO if $gid == $tryno;
		}
		last NEXTNO;
	}
	die "Cannot find free gid\n" if $tryno == 65536;
	warn "Will create $name as gid $tryno\n"; 
	system "niutil -create / /groups/$name";
	system "niutil -createprop / /groups/$name name $name";
	system "niutil -createprop / /groups/$name gid $tryno";
	system "niutil -createprop / /groups/$name passwd '*'";
	return $tryno;
}

sub addusertogroup
{
	my $user = shift;
	my $group = shift;
	system "niutil -appendprop / /groups/$group users $user";
}

sub readgroups
{
	open( NIDUMP, "nidump group /|") or die "Cannot run nidump\n";
	my @groups=<NIDUMP>;
	close( NIDUMP);
	return @groups;
}

sub readusers
{
	my @passwd;
	open( NIDUMP, "nidump passwd /|") or die "Cannot run nidump\n";
	@passwd=<NIDUMP>;
	close( NIDUMP);
	return @passwd;
}

sub createuser
{
	my $name = shift;
	my $realname = shift;
	my $shell = shift;
	my $home = shift;
	my $gid = shift;

	open( NIDUMP, "nidump passwd /|") or die "Cannot run nidump\n";
	my @passwd=<NIDUMP>;
	close( NIDUMP);

	my $tryno;
	NEXTNO: for ($tryno = 88; $tryno <= 65535; $tryno++) {
		foreach my $passwd (@passwds) {
			(my $passwdname, undef, my $uid, undef) =
				split( ':', $passwd);
			next NEXTNO if $uid == $tryno;
		}
		last NEXTNO;
	}
	die "Cannot find free uid\n" if $tryno == 65536;
	warn "Will create $name as uid $tryno\n"; 
	system "niutil -create / /users/$name";
	system "niutil -createprop / /users/$name realname $realname";
	system "niutil -createprop / /users/$name shell $shell";
	system "niutil -createprop / /users/$name uid $tryno";
	system "niutil -createprop / /users/$name gid $gid";
	system "niutil -createprop / /users/$name home $home";
	system "niutil -createprop / /users/$name _shadow_passwd";
	system "niutil -createprop / /users/$name passwd '*'";
	return $tryno;
}

