#!/usr/local/bin/perl
# save_group.cgi
# Saves or creates a new group

require './ldap-useradmin-lib.pl';
&error_setup($text{'gsave_err'});
&ReadParse();
$ldap = &ldap_connect();

if (!$in{'new'}) {
	# Get existing group
	$rv = $ldap->search(base => $in{'dn'},
			    scope => 'base',
			    filter => '(&(objectClass=posixGroup))');
	($ginfo) = $rv->all_entries;
	$ginfo || &error($text{'gsave_egone'});
	%ogroup = &dn_to_hash($ginfo);
	}

if ($in{'delete'}) {
	# Delete the group, but first check if it is anyone's primary group,
	# and ask first
	&ui_print_header(undef, $text{'gdel_title'}, "");

	if ($in{'confirm'}) {
		# Delete from other modules
		%group = &dn_to_hash($ginfo);
		if ($in{'others'}) {
			print "$text{'gdel_other'}<br>\n";
			&useradmin::other_modules("useradmin_delete_group",
						  \%group);
			print "$text{'gdel_done'}<p>\n";
			}

		# Delete the LDAP entry
		print "$text{'gdel_group'}<br>\n";
		$rv = $ldap->delete($in{'dn'});
		if ($rv->code) {
			&error(&text('gsave_edelete', $rv->error));
			}
		print "$text{'gdel_done'}<p>\n";

		%p = ( %in, %group );
		&webmin_log('delete', 'group', $group{'group'}, \%p);
		}
	else {
		# Check if any user has this group as his primary
		$gid = $ginfo->get_value("gidNumber");
		$group = $ginfo->get_value("cn");

		setpwent();
		while(@uinfo = getpwent()) {
			if ($uinfo[3] == $gid) {
				$found = $uinfo[0];
				last;
				}
			}
		endpwent();

		if ($found) {
			# Cannot delete
			print "<p><b>",&text('gdel_eprimary', $found),
			      "</b> <p>\n";
			}
		else {
			# Ask the user if he is sure
			print "<form action=save_group.cgi>\n";
			print "<input type=hidden name=dn value=\"$in{'dn'}\">\n";
			print "<input type=hidden name=delete value=1>\n";
			print "<input type=hidden name=confirm value=1>\n";
			print "<center><h3>",&text('gdel_sure', $group),"</h3>\n";
			print "<input type=submit value=\"$text{'gdel_del'}\">\n";

			printf "<br><input type=checkbox name=others value=1 %s> %s<br>\n",
				$uconfig{'default_other'} ? "checked" : "",
				$text{'gdel_dothers'};
			print "</center><p>\n";
			print "</form>\n";
			}
		}

	$ldap->unbind();
	&ui_print_footer("", $text{'index_return'});
	exit;
	}

# Strip out \n characters in inputs
$in{'group'} =~ s/\r|\n//g;
$in{'pass'} =~ s/\r|\n//g;
$in{'encpass'} =~ s/\r|\n//g;
$in{'gid'} =~ s/\r|\n//g;

# Validate inputs
if ($in{'new'}) {
	$in{'group'} =~ /^[^:\t]+$/ ||
		&error(&text('gsave_ebadname', $in{'group'}));
	$group = $in{'group'};
	}
else {
	$group = $in{'group'};
	$oldgroup = $ginfo->get_value("cn");
	}
$in{'gid'} =~ /^[0-9]+$/ || &error(&text('gsave_egid', $in{'gid'}));
$gid = $in{'gid'};
@members = split(/\s+/, $in{members});
if ($in{'new'} || $oldgroup ne $group) {
	# Check for collision
	defined(getgrnam($group)) && &error(&text('gsave_einuse', $group));
	}

$pfx = $config{'md5'} == 1 || $config{'md5'} == 3 ? "{md5}" :
       $config{'md5'} == 0 ? "{crypt}" : "";
if ($in{'passmode'} == 0) {
	$pass = "";
	}
elsif ($in{'passmode'} == 1) {
	$pass = $in{'encpass'};
	$pass = $pfx.$pass if ($pass !~ /^\{[a-z0-9]+\}/i && $pfx);
	}
elsif ($in{'passmode'} == 2) {
	$pass = $pfx.&encrypt_password($in{'pass'});
	}

if (!$in{'new'}) {
	# Change GID on files if needed
	$oldgid = $ginfo->get_value("gidNumber");
	if ($gid != $oldgid && $in{'chgid'}) {
		if ($in{'chgid'} == 1) {
			# Do all the home directories of users in this group
			setpwent();
			while(@tmp = getpwent()) {
                                if ($tmp[3] == $oldgid ||
                                    &indexof($tmp[0], @members) >= 0) {
                                        &useradmin::recursive_change(
                                                $tmp[7], -1, $oldgid,
                                                         -1, $gid);
                                        }
                                }
                        endpwent();
			}
		else {
			# Do all files in this group from the root dir
			&useradmin::recursive_change("/", -1, $oldgid,
						     -1, $gid);
			}
		}

	# Update the LDAP database
	$rv = $ldap->modify($in{'dn'}, replace =>
			    { "gidNumber" => $gid,
			      "cn" => $group,
			      "userPassword" => $pass,
			      @members ? ( "memberUid" => \@members ) : ( ) } );
	if ($rv->code) {
		&error(&text('gsave_emod', $rv->error))
		}
	if (!@members && $ginfo->get_value("memberUid")) {
		$rv = $ldap->modify($in{'dn'}, delete => [ "memberUid" ] );
		if ($rv->code) {
			&error(&text('gsave_emod', $rv->error))
			}
		}

	if ($oldgroup ne $group) {
	        # Need to rename the LDAP dn itself
	        $base = &get_group_base();
	        $newdn = "cn=$group,$base";
	        $rv = $ldap->moddn($in{'dn'}, newrdn => "cn=$group");
	        if ($rv->code) {
	                &error(&text('gsave_emoddn', $rv->error));
	                }
	        }
	}
else {
	# Add to the LDAP database
	$base = &get_group_base();
	$newdn = "cn=$group,$base";
	$rv = $ldap->add($newdn, attr =>
			 [ "cn" => $group,
			   "gidNumber" => $gid,
			   "userPassword" => $pass,
			   @members ? ( "memberUid" => \@members ) : ( ),
			   "objectClass" => [ "posixGroup" ] ] );
	if ($rv->code) {
		&error(&text('gsave_eadd', $rv->error));
		}
	}

# Run other module's scripts
if ($in{'others'}) {
	if (!$in{'new'}) {
		&useradmin::other_modules("useradmin_modify_group", \%group, \%ogroup);
		}
	else {
		&useradmin::other_modules("useradmin_create_group", \%group);
		}
	}

delete($in{'pass'});
delete($in{'encpass'});
$ldap->unbind();
&webmin_log(!$in{'new'} ? 'modify' : 'create', 'group', $group, \%in);

# Bounce back to the list
&redirect("");

# dn_to_hash(&ldap-object)
sub dn_to_hash
{
local %group = ( 'group' => $_[0]->get_value("cn"),
                 'gid' => $_[0]->get_value("gidNumber"),
                 'pass' => $_[0]->get_value("userPassword"),
		 'members' => join(",", $_[0]->get_value("memberUid")) );
$group{'pass'} =~ s/^{[a-z0-9]+}//i;
return %group;
}

