#!/usr/local/bin/perl # Execute create/modify/delete group commands in a batch file require './user-lib.pl'; $access{'batch'} || &error($text{'gbatch_ecannot'}); if ($ENV{'REQUEST_METHOD'} eq 'GET') { &ReadParse(); } else { &ReadParseMime(); } if ($in{'source'} == 0) { $data = $in{'file'}; $data =~ /\S/ || &error($text{'batch_efile'}); } elsif ($in{'source'} == 1) { open(LOCAL, $in{'local'}) || &error($text{'batch_elocal'}); while() { $data .= $_; } close(LOCAL); } elsif ($in{'source'} == 2) { $data = $in{'text'}; $data =~ /\S/ || &error($text{'batch_etext'}); } &ui_print_unbuffered_header(undef, $text{'gbatch_title'}, ""); # Force defaults for save options $in{'chgid'} = 1 if (!$access{'chgid'}); # Work out a good base GID for new groups &build_group_used(\%gused, \%gtaken); $newgid = int($config{'base_gid'} > $access{'lowgid'} ? $config{'base_gid'} : $access{'lowgid'}); # Process the file &batch_start() if ($in{'batch'}); &lock_user_files(); $lnum = $created = $modified = $deleted = 0; print "
\n";
$pft = &passfiles_type();
foreach $line (split(/[\r\n]+/, $data)) {
	$lnum++;
	$line =~ s/^\s*#.*$//;
	next if ($line !~ /\S/);
	local @line = split(/:/, $line, -1);
	local %group;
	if ($line[0] eq 'create') {
		# Creating a new group

		# Validate line
		if (!$line[1]) {
			print &text('batch_eline', $lnum),"\n";
			next;
			}
		if (@line != 5) {
			print &text('batch_elen', $lnum, 5),"\n";
			next;
			}
		if ($line[1] !~ /^[^:\t]+$/) {
			print &text('gbatch_egroupname', $lnum),"\n";
			next;
			}
		$group{'group'} = $line[1];

		if ($gtaken{$group{'group'}}) {
			print &text('gbatch_egroup', $lnum,
				    $group{'group'}),"\n";
			next;
			}
		if ($line[3] !~ /^\d+$/) {
			# make up a GID
			while($gused{$newgid}) {
				$newgid++;
				}
			$group{'gid'} = $newgid;
			}
		else {
			# use the given UID
			if ($gused{$line[3]} && !$access{'gmultiple'}) {
				print &text('gbatch_ecaccess', $lnum,
					    $text{'gsave_egidused2'}),"\n";
				next;
				}
			$group{'gid'} = $line[3];
			}
		$gused{$group{'gid'}}++;
		$group{'members'} = $line[4];

		# Check access control restrictions
		if (!$access{'gcreate'}) {
			print &text('gbatch_ecaccess', $lnum,
				    $text{'gsave_ecreate'});
			next;
			}
		local $ch = &check_group(\%group);
		if ($ch) {
			print &text('gbatch_ecaccess', $lnum, $ch),"\n";
			next;
			}

		if ($line[2] eq '') {
			# No password needed
			$group{'pass'} = '';
			$group{'passmode'} = 0;
			}
		else {
			# Normal password
			$group{'pass'} = &encrypt_password($line[2]);
			$group{'passmode'} = 3;
			$group{'plainpass'} = $line[2];
			}

		# Run the before command
		&set_user_envs(\%group, 'CREATE_GROUP');
		$merr = &making_changes();
		&error(&text('gsave_emaking', "$merr"))
			if (defined($merr));

		# Create the group!
		&create_group(\%group);

		# All done
		&made_changes();

		# Call other modules, ignoring any failures
		$error_must_die = 1;
		eval {
			&other_modules("useradmin_create_group", \%group)
				if ($access{'cothers'} == 1 && $in{'others'} ||
				    $access{'cothers'} == 0);
			};
		$other_err = $@;
		$error_must_die = 0;

		print "",&text('gbatch_created', $group{'group'}),"\n";
		print "",&text('batch_eother', $other_err),"\n"
			if ($other_err);
		$created++;
		}
	elsif ($line[0] eq 'delete') {
		# Deleting an existing group
		if (@line != 2) {
			print &text('batch_elen', $lnum, 2),"\n";
			next;
			}
		local @glist = &list_groups();
		local ($group) = grep { $_->{'group'} eq $line[1] } @glist;
		if (!$group) {
			print &text('gbatch_enogroup', $lnum, $line[1]),"\n";
			next;
			}

		# Check if deletion is allowed
		if (!&can_edit_group(\%access, $group)) {
			print &text('gbatch_edaccess', $lnum,
				    $text{'gdel_egroup'}),"\n";
			next;
			}
		if (!$config{'delete_root'} && $group->{'gid'} <= 10) {
			print &text('gbatch_edaccess', $lnum,
				    $text{'gdel_egroup'}),"\n";
			next;
			}

		# Check if has primary members
		local $prim;
		foreach $u (&list_users()) {
			if ($u->{'gid'} == $group->{'gid'}) {
				$prim = $u;
				last;
				}
			}
		if ($prim) {
			print &text('gbatch_eprimary', $lnum,
				    $prim->{'user'}),"\n";
			next;
			}

		# Run the before command
		&set_user_envs($group, 'DELETE_GROUP');
		$merr = &making_changes();
		&error(&text('usave_emaking', "$merr"))
			if (defined($merr));

		# Delete from other modules, ignoring errors
		$error_must_die = 1;
		eval {
			&other_modules("useradmin_delete_group", $group)
				if ($access{'dothers'} == 1 && $in{'others'} ||
				    $access{'dothers'} == 0);
			};
		$other_err = $@;
		$error_must_die = 0;

		# Delete the user entry
		&delete_group($group);

		&made_changes();

		print "",&text('gbatch_deleted',$group->{'group'}),"\n";
		print "",&text('batch_eother', $other_err),"\n"
			if ($other_err);
		$deleted++;
		}
	elsif ($line[0] eq 'modify') {
		# Modifying an existing group
		if (@line != 6) {
			print &text('batch_elen', $lnum, 6),"\n";
			next;
			}
		local @glist = &list_groups();
		local ($group) = grep { $_->{'group'} eq $line[1] } @glist;
		if (!$group) {
			print &text('gbatch_enogroup', $lnum, $line[1]),"\n";
			next;
			}
		%oldgroup = %group = %$group;
		$user{'olduser'} = $user->{'user'};
		if (!&can_edit_group(\%access, \%group)) {
			print &text('gbatch_emaccess', $lnum,
				    $text{'gsave_eedit'}),"\n";
			next;
			}

		# Update supplied fields
		if ($line[2] ne '') {
			if (!$access{'grename'}) {
				print &text('gbatch_erename',
					    $lnum, $line[1]),"\n";
				}
			$group{'group'} = $line[2];
			}
		if ($line[3] ne '') {
			# New normal password
			$group{'pass'} = &encrypt_password($line[3]);
			$group{'passmode'} = 3;
			$group{'plainpass'} = $line[3];
			}
		else {
			# No change
			$group{'passmode'} = 4;
			}
		$group{'gid'} = $line[4] if ($line[4] ne '');
		if ($line[5] =~ /^\s+$/ || $line[5] eq 'NONE') {
			# No members
			$group{'members'} = '';
			}
		elsif ($line[5]) {
			$group{'members'} = $line[5];
			}

		# Check access control restrictions
		local $ch = &check_group(\%group, \%oldgroup);
		if ($ch) {
			print &text('gbatch_emaccess', $lnum, $ch),"\n";
			next;
			}

		# Run the before command
		&set_user_envs(\%group, 'MODIFY_GROUP');
		$merr = &making_changes();
		&error(&text('usave_emaking', "$merr"))
			if (defined($merr));

		# Change GIDs
		if ($oldgroup{'gid'} != $group{'gid'} && $in{'chgid'}) {
			if ($in{'chgid'} == 1) {
				# Do all the home directories of members
				&change_all_home_groups(
					$oldgroup{'gid'}, $group{'gid'},
					[ split(/,/, $group{'members'}) ]);
				}
			else {
				# Do all files in this group from the root dir
				&recursive_change("/", -1, $oldgroup{'gid'},
						       -1, $group{'gid'});
				}
			}

		# Actually modify the group
		&modify_group(\%oldgroup, \%group);
		&made_changes();

		# Modify in other modules, ignoring errors
		$error_must_die = 1;
		eval {
			&other_modules("groupadmin_modify_group",
				       \%group, \%oldgroup)
				if ($access{'mothers'} == 1 && $in{'others'} ||
				    $access{'mothers'} == 0);
			};
		$error_must_die = 0;
		$other_err = $@;

		print "",&text('batch_modified',$oldgroup{'group'}),"\n";
		print "",&text('batch_eother', $other_err),"\n"
			if ($other_err);
		$modified++;
		}
	else {
		print &text('batch_eaction', $lnum, $line[0]),"\n";
		next;
		}
	}
print "
\n"; &batch_end() if ($in{'batch'}); &unlock_user_files(); &webmin_log("gbatch", undef, $in{'source'} == 1 ? $in{'local'} : undef, { 'created' => $created, 'modified' => $modified, 'deleted' => $deleted, 'lnum' => $lnum } ); &ui_print_footer("gbatch_form.cgi", $text{'batch_return'}, "index.cgi?mode=groups", $text{'index_return'}); # check_group(\%group, [\%oldgroup]) # Check access control restrictions for a group sub check_group { # check if gid is within range if ($access{'lowgid'} && $_[0]->{'gid'} < $access{'lowgid'}) { return &text('usave_elowgid', $access{'lowuid'}); } if ($access{'hiuid'} && $_[0]->{'uid'} > $access{'hiuid'}) { return &text('usave_ehiuid', $access{'hiuid'}); } if ($_[1] && !$access{'ggid'} && $_[1]->{'gid'} != $_[0]->{'gid'}) { return $text{'gsave_eggid'}; } return undef; }