#! /usr/bin/perl -Idebian/tests/lib

# check uidgidpool functionality for system users/groups

use diagnostics;
use strict;
use warnings;

use AdduserTestsCommon;
use Test::More;

my @quiet=("--stdoutmsglevel=error", '--stderrmsglevel=error');

my $cl_user = AdduserTestsCommon::AdduserTestCleanup->new(
    \&cleanup_user
);
my $cl_tree = AdduserTestsCommon::AdduserTestCleanup->new(
    \&cleanup_tree
);


# single pool file
my $uidpoolfile="/etc/adduser-uidpool.conf";
my $gidpoolfile="/etc/adduser-gidpool.conf";
my $poolbasedir="/etc/adduser-pool.d";
my $uidpooldir="$poolbasedir/uid";
my $gidpooldir="$poolbasedir/gid";
my %confhash;
$cl_tree->add(qw(/etc/adduser-uidpool.conf /etc/adduser-gidpool.conf));
$cl_tree->add(qw(/etc/adduser-pool.d));

my $auid=341;
my $agid=334;
my $ashell="/bin/dash";
my $acomment="alternate comment";

my @suidlist = (
   {
    'name' => 'spooluid201',
    'id' => 201,
    'comment' => 'spooluid201 pool account',
    'home' => '/home/spool201',
    'ahome' => '/home/salt201',
    'shell' => '/bin/bash',
   },{
    'name' => 'spooluid232',
    'id' => 232,
    'comment' => 'spooluid232 pool account',
    'home' => '/home/spool232',
    'ahome' => '/home/salt232',
    'shell' => '/bin/sh',
   }
);
$cl_tree->add(qw(/home/spool201 /home/spool232));
$cl_user->add(qw(spooluid201 spooluid232));
my $firstuid = (sort map {$_->{id}} @suidlist)[0];

my @suidreserved = (
   {
    'name' => 'suidreserved1',
    'id' => $firstuid,
    'comment' => 'suidreserved1 pool account',
    'home' => '/home/suidreserved1',
    'ahome' => '/home/sauidreserved1',
    'shell' => '/bin/sh',
   }
);
$cl_tree->add(qw(/home/suidreserved1 /home/sauidreserved1));
$cl_user->add(qw(suidreserved1));

my @sgidlist = (
    {
     name => 'spoolgid321',
     id => 321,
    },{
     name => 'spoolgid322',
     id => 322,
    }
);
my $firstgid = (sort map {$_->{id}} @sgidlist)[0];
my @sgidreserved = (
   {
    name => 'sgidreserved1',
    id => $firstgid,
   }
);
$cl_user->add(qw(spoolgid321 spoolgid322 sgidreserved1));

# test creating user/group without uidpool set

foreach my $group( @sgidlist ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--comment', '""', '--disabled-password', $group->{name});
    assert_group_exists($group->{name});
    assert_gid_does_not_exist($group->{id});
}

foreach my $user( @suidlist ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_uid_does_not_exist($user->{id});
}

sub cleanup {
    foreach my $user( @suidlist, @suidreserved ) {
        system("/usr/sbin/deluser @quiet --system --remove-home $user->{name} 2>/dev/null");
        assert_user_does_not_exist($user->{name});
    }
    foreach my $group( @sgidlist, @sgidreserved ) {
        system("/usr/sbin/delgroup @quiet --system $group->{name} 2>/dev/null");
        assert_group_does_not_exist($group->{name});
    }
}
cleanup();



# create test pool files
my $fh;
open ($fh, ">>", $uidpoolfile) or die "Failed to open file $uidpoolfile for writing";
foreach my $idset( @suidlist ) {
    print $fh $idset->{name}. ":". $idset->{id}. ":". $idset->{comment}. ":". $idset->{home}. ":". $idset->{shell}. "\n"
}

open ($fh, ">>", $gidpoolfile) or die "Failed to open file $gidpoolfile for writing";
foreach my $idset( @sgidlist ) {
    print $fh $idset->{name}. ":". $idset->{id}. "\n"
}

# configure adduser to use uidpool
%confhash=();
$confhash{"UID_POOL"}="$uidpoolfile";
$confhash{"GID_POOL"}="$gidpoolfile";
apply_config_hash(\%confhash);

# test creating user/group with uidpool set

foreach my $group( @sgidlist ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $group->{id});
    cleanup();

    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--gid', $agid, $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $agid);
    cleanup();
}

foreach my $user( @suidlist ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--uid', $auid, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $auid);
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', $acomment, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $acomment);
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--home', $user->{ahome}, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{ahome});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--shell', $ashell, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $ashell);
    cleanup();
}

%confhash=();
$confhash{"UID_POOL"}="$uidpoolfile";
$confhash{"GID_POOL"}="$gidpoolfile";
$confhash{"FIRST_SYSTEM_UID"}="$firstuid";
$confhash{"FIRST_SYSTEM_GID"}="$firstgid";
$confhash{"RESERVE_UID_POOL"}="no";
$confhash{"RESERVE_GID_POOL"}="no";
apply_config_hash(\%confhash);

# test not reserved uid in pool

foreach my $group( @sgidreserved ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $group->{id});
    cleanup();

    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--gid', $agid, $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $agid);
    cleanup();
}

foreach my $user( @suidreserved ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    cleanup();
}

%confhash=();
$confhash{"UID_POOL"}="$uidpoolfile";
$confhash{"GID_POOL"}="$gidpoolfile";
$confhash{"FIRST_SYSTEM_UID"}="$firstuid";
$confhash{"FIRST_SYSTEM_GID"}="$firstgid";
$confhash{"RESERVE_UID_POOL"}="yes";
$confhash{"RESERVE_GID_POOL"}="yes";
apply_config_hash(\%confhash);

# test reserved uid in pool

foreach my $group( @sgidreserved ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      $group->{name});
    assert_group_exists($group->{name});
    assert_gid_does_not_exist($group->{id});
    cleanup();

    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--gid', $group->{id}, $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $group->{id});
    cleanup();
}

foreach my $user( @suidreserved ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_uid_does_not_exist($user->{id});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--uid', $user->{id}, '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    cleanup();
}

%confhash=();
$confhash{"UID_POOL"}="$uidpoolfile";
$confhash{"GID_POOL"}="$gidpoolfile";
$confhash{"FIRST_SYSTEM_UID"}="$firstuid";
$confhash{"FIRST_SYSTEM_GID"}="$firstgid";
$confhash{"RESERVE_UID_POOL"}="no";
$confhash{"RESERVE_GID_POOL"}="no";
apply_config_hash(\%confhash);

# test not reserved uid in pool

foreach my $group( @sgidreserved ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $group->{id});
    cleanup();

    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--gid', $agid, $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $agid);
    cleanup();
}

foreach my $user( @suidreserved ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    cleanup();
}

%confhash=();
$confhash{"UID_POOL"}="$uidpoolfile";
$confhash{"GID_POOL"}="$gidpoolfile";
$confhash{"FIRST_SYSTEM_UID"}="$firstuid";
$confhash{"FIRST_SYSTEM_GID"}="$firstgid";
$confhash{"RESERVE_UID_POOL"}="yes";
$confhash{"RESERVE_GID_POOL"}="yes";
apply_config_hash(\%confhash);

# test reserved uid in pool

foreach my $group( @sgidreserved ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      $group->{name});
    assert_group_exists($group->{name});
    assert_gid_does_not_exist($group->{id});
    cleanup();

    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--gid', $group->{id}, $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $group->{id});
    cleanup();
}

foreach my $user( @suidreserved ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_uid_does_not_exist($user->{id});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--uid', $user->{id}, '--comment', '""', '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    cleanup();
}

# remove test pool files
assert_command_success('rm', '-f', $uidpoolfile, $gidpoolfile);

# create and fill test pool directories
assert_command_success('mkdir', '-p', $uidpooldir, $gidpooldir);
my $counter=1;
foreach my $idset( @suidlist ) {
    my $fn = $uidpooldir. "/uidpool". $counter. ".conf";
    open (my $fh, ">>", $fn) or die "Failed to open file $fn for writing";
    print $fh $idset->{name}. ":". $idset->{id}. ":". $idset->{comment}. ":". $idset->{home}. ":". $idset->{shell}. "\n";
    $counter++;
}

foreach my $idset( @sgidlist ) {
    my $fn = $gidpooldir. "/gidpool". $counter. ".conf";
    open (my $fh, ">>", $fn) or die "Failed to open file $fn for writing";
    print $fh $idset->{name}. ":". $idset->{id}. "\n";
    $counter++;
}

# configure adduser to use uidpool
%confhash=();
$confhash{"UID_POOL"}="$uidpooldir";
$confhash{"GID_POOL"}="$gidpooldir";
apply_config_hash(\%confhash);

# test creating user/group with uidpool set

foreach my $group( @sgidlist ) {
    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $group->{id});
    cleanup();

    assert_command_success('/usr/sbin/addgroup', @quiet, "--system",
      '--gid', $agid, $group->{name});
    assert_group_exists($group->{name});
    assert_group_has_gid($group->{name}, $agid);
    cleanup();
}

foreach my $user( @suidlist ) {
    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--uid', $auid, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $auid);
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--comment', $acomment, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $acomment);
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--home', $user->{ahome}, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{ahome});
    assert_user_has_login_shell($user->{name}, $user->{shell});
    cleanup();

    assert_command_success('/usr/sbin/adduser', @quiet, "--system",
      '--shell', $ashell, '--disabled-password', $user->{name});
    assert_user_exists($user->{name});
    assert_user_has_uid($user->{name}, $user->{id});
    assert_user_has_comment($user->{name}, $user->{comment});
    assert_user_has_home_directory($user->{name}, $user->{home});
    assert_user_has_login_shell($user->{name}, $ashell);
    cleanup();
}

$cl_user->finalize();
$cl_tree->finalize();
done_testing();

# vim: tabstop=4 shiftwidth=4 expandtab
