#!/usr/bin/perl 
# $OpenBSD: createuser,v 1.2 1999/08/21 20:56:05 niklas Exp $

# user creation script.
# All ports that need to create new users should defer to this script
# If specific capabilities are needed they should be added HERE as well.

require '/usr/ports/infrastructure/db/user.db';

use Fcntl ':flock'; # import LOCK_* constants

sub check_root
	{
	if ($>) 
		{ die "Only root can run this script\n"; } 
	if ($<)
		{ die "There is something fishy going on, I'd better quit\n"; }
	}

sub fill_user
	{
	my ($key) = shift;
	unless (defined $users{$key})
		{die "Sorry, no such user: $key, maybe you need to upgrade your createuser database ?\n"; }
	my ($r) = $users{$key};
	unless (defined $r->{fullname} && defined $r->{uid})
		{ die "Incompletely defined user: $key\n"; }
	$r->{user} = $key unless defined $r->{user};
	$r->{group} = $r->{user} unless defined $r->{group};
	$r->{gid} = $r->{uid} unless defined $r->{gid};
	$r->{shell} = '/sbin/nologin' unless defined $r->{shell};
	$r->{home} = '/root' unless defined $r->{home};
		# avoid characters such as + or : in password entries...

	my $k;
	local $_;
	while (($k, $_) = each %$r)
		{ die "Bad chpass field $_\n" unless m/^[\d\w ()\-\/.]+$/; }
	return $r;
	}

sub atomic_append 
	{
	my ($file,@list) = @_;

	open F, ">> $file"  or die "$file: $!\n";
	unless (flock(F, LOCK_EX | LOCK_NB))
		{ die "Cannot lock $file\n"; }
		# prevent the rare case where someone is already appending to that file
	seek F, 0, 2;
	print F join( "\n", @list) . "\n";
	close F;
	flock  F, LOCK_UN ;
	}


# the main routine

check_root();
if ($#ARGV < 0)
	{ die "Must supply one argument\n"; }


my $r = fill_user($ARGV[0]);

my ($uid, $gid);

# find matching uid/gids.
unless ( $uid = (getpwnam $r->{user})[2])
	{
	$uid = $r->{uid};
	$uid++ while getpwuid $uid;
	}

unless ( $gid = (getgrnam $r->{group})[2])
	{
	$gid = $r->{gid};
	$gid++ while getgrgid $gid;
	}

# check mandatory ids
if ($r->{mandatory} =~ m/uid/ && $uid != $r->{uid})
	{ die "Uid mismatch for $r->{user}\n"; }
if ($r->{mandatory} =~ m/gid/ && $gid != $r->{gid})
	{ die "Gid mismatch for $r->{user}\n"; }

atomic_append( '/etc/group', "$r->{group}:*:$gid:" );

print "$r->{user} with uid $uid, of group $r->{group} with gid $gid\n";

$passargs = join(':', 
	($r->{user}, '*', $uid, $gid, '', '', '', $r->{fullname}, $r->{home}, $r->{shell}));
$local = `ypwhich >/dev/null 2>&1 && echo -n l`;
print "/usr/bin/chpass -${local}a $passargs\n";
system('/usr/bin/chpass', "-${local}a", $passargs);