smeserver-lazy_admin_tools/root/usr/sbin/lat-groups

424 lines
15 KiB
Perl

#!/usr/bin/perl -w
#==============================================================================
# lat-groups
# ==========
# 0.9.0 (2004-09-08)
# (c)2003-2004 Altiplano bvba
#==============================================================================
package esmith;
use strict;
use esmith::db;
use esmith::util;
use Pod::Usage;
use Getopt::Long;
my %conf;
tie %conf, 'esmith::config';
my %accounts;
tie %accounts, 'esmith::config', '/home/e-smith/db/accounts';
my ($Hlp, $Cml, $Frc, $Inp, $Noa);
my $Add =0;
my $Del =0;
my $Rem =0;
#==============================================================================
# Main
#==============================================================================
# Analyze commandline options
GetOptions ("help" => \$Hlp,
"add" => \$Add,
"delete" => \$Del,
"force" => \$Frc,
"no-admin", => \$Noa,
"remove-user" => \$Rem,
"command-line=s" => \$Cml,
"input-file=s" => \$Inp);
if ( $Hlp ) { &PrintPod(9); exit; }
# We need one argument or the other, but not both
if ((($Cml && $Inp && $Rem) || (! $Cml && ! $Inp && ! $Rem)) ||
($Add + $Del + $Rem != 1))
{ &PrintPod(1); exit; }
my @records;
if ($Inp) {
open(LIST,"< $Inp") || die "Can't find $Inp.\n";
@records = grep(!/(^\s*#)|(^\s*$)/,<LIST>);
close(LIST); }
elsif ($Cml) { @records=($Cml); }
else { &PrintPod(1); exit; }
# Add groups
if ($Add) {
# Process each group
foreach my $record (@records) {
my @fields=split(/\|/,$record);
for (my $cnt=0; $cnt <= $#fields; ++$cnt) { for ($fields[$cnt]) { s/^\s+//; s/\s+$//; }}
my $groupname = $fields[0];
# We need a valid group name
if ( ! &TestName($fields[0])) { exit; }
# Create the group, if needed
if ( ! db_get(\%accounts, $groupname)) {
# Find a usable GID
my $gid;
if ($fields[2]) { $gid = $fields[2]; }
else { $gid = &FindUid;}
if (&TestUid($gid)) {
my %group = ("Description", $fields[1],
"Uid",$gid,
"Gid",$gid,
"Members","");
print "Creating group '$fields[0]' (GID:$gid).\n";
db_set(\%accounts, $groupname, 'group', \%group);
system("/sbin/e-smith/signal-event", "group-create", $groupname) == 0
or die ("An error occurred while creating group $groupname.\n\a");
}
}
# Add the members to the group, if they are valid accounts
if ( db_get_type(\%accounts, $groupname) eq "group" ) {
for (my $cnt=3; $cnt < @fields; ++$cnt ) {
# Check if this user exists on the server
if (((db_get(\%accounts, $fields[$cnt])) &&
(db_get_type(\%accounts, $fields[$cnt])) eq "user") ||
($fields[$cnt] eq 'admin')) {
# Is she already a member of this group?
my $members = db_get_prop(\%accounts, $groupname, 'Members');
if (! $members) { $members="" }
if (! ($members =~ m/\b$fields[$cnt]\b/)) {
# Append the new member to the list and update the group
if (length($members) > 0) { $members=$members.",";}
$members = $members."$fields[$cnt]";
print "Adding user '$fields[$cnt]' to group '$fields[0]'.\n";
db_set_prop(\%accounts, $groupname, 'Members', $members);
system("/sbin/e-smith/signal-event", "group-modify", $groupname) == 0
or die ("An error occurred while updating group $groupname.\n\a");
}
}
else { print "User '$fields[$cnt]' doesn't exist on this server.\n\a"; }
}
}
else { print "Error: '$groupname' is not a valid group name on this system.\a\n"; }
# Remove 'admin' and 'www' from /etc/group if we don't want them.
if ($Noa) {
system("/usr/bin/gpasswd -d www $groupname > /dev/null");
system("/usr/bin/gpasswd -d admin $groupname > /dev/null");
}
}
}
# Delete groups
if ($Del) {
&ExpandWildCard; # Check for wildcards and expand if necessary
# Process each group
foreach my $record (@records) {
my @fields=split(/\|/,$record);
for (my $cnt=0; $cnt <= $#fields; ++$cnt) { for ($fields[$cnt]) { s/^\s+//; s/\s+$//; }}
my $groupname = $fields[0];
# Silly, but if 'www' and 'admin' aren't member of this group an error message will be shown :-/
system("/usr/bin/gpasswd -a www $groupname > /dev/null");
system("/usr/bin/gpasswd -a admin $groupname > /dev/null");
if ((db_get_type(\%accounts, $groupname)) &&
(db_get_type(\%accounts, $groupname)) eq 'group')
{
my $yn = 'yes';
if (! $Frc) {
print "Delete group '$groupname' [yes/NO/all]? "; $yn = <STDIN>;
if ($yn =~ /^a/i) { $Frc = -1; $yn="yes"; }
}
if ($yn =~ /^y/i) {
print "Deleting group '$groupname'.\n";
db_delete(\%accounts, $groupname);
system("/sbin/e-smith/signal-event", "group-delete", $groupname);
}
}
else { print "Group '$groupname' doesn't exist on this server.\n\a"; }
}
}
# Remove users from group
if ($Rem) {
&ExpandWildCard; # Check for wildcards and expand if necessary
# Process each group
foreach my $record (@records) {
my @fields=split(/\|/,$record);
for (my $cnt=0; $cnt <= $#fields; ++$cnt) { for ($fields[$cnt]) { s/^\s+//; s/\s+$//; }}
my $groupname = $fields[0];
if ( db_get(\%accounts, $groupname)) {
# Remove the members from the group
for (my $cnt=1; $cnt < @fields; ++$cnt ) {
my $members = db_get_prop(\%accounts, $groupname, 'Members');
if (! $members) { $members="" }
my $yn = 'yes';
if (! $Frc) {
print "Remove user '$fields[$cnt]' from group '$groupname' [yes/NO/all]? "; $yn = <STDIN>;
if ($yn =~ /^a/i) { $Frc = -1; $yn="yes"; }
}
if ($yn =~ /^y/i) {
print "Removing member '$fields[$cnt]' from group '$fields[0]'.\n";
$members =~ s/$fields[$cnt]//;
$members =~ s/,,/,/ ;
$members =~ s/(^,)|(,$)//;
db_set_prop(\%accounts, $groupname, 'Members', $members);
system("/sbin/e-smith/signal-event", "group-modify", $groupname) == 0
or die ("An error occurred while updating group $groupname.\n\a");
}
}
}
else { print "The group '$groupname' does not exist on this server.\n\a"; }
}
}
#==============================================================================
# Subroutines
#==============================================================================
# Find an unused Uid/Gid
sub FindUid {
open(ACC,"/home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts";
my @recs = grep(/Uid\|\d*/,<ACC>);
close(ACC);
open(PWD,"/etc/passwd") || die "Can't find /etc/passwd";
my @pwds = grep(/\:\d*\:/,<PWD>);
close(PWD);
open(GRP,"/etc/group") || die "Can't find /etc/group";
my @grps = grep(/\:\d*\:/,<GRP>);
close(GRP);
my $newuid=db_get(\%conf, 'MinUid');
do { ++$newuid;} until ((! grep(/Uid\|$newuid\D/,@recs)) &&
(! grep(/\:$newuid\:/,@pwds)) &&
(! grep(/\:$newuid\:/,@grps)));
return $newuid;
}
#==============================================================================
# Test the gid for availability and legality
sub TestUid {
open(ACC,"/home/e-smith/db/accounts") || die "Can't find /home/e-smith/db/accounts";
my @recs = grep(/Gid\|\d*/,<ACC>);
close(ACC);
open(PWD,"/etc/passwd") || die "Can't find /etc/passwd";
my @pwds = grep(/\:\d*\:/,<PWD>);
close(PWD);
open(GRP,"/etc/group") || die "Can't find /etc/group";
my @grps = grep(/\:\d*\:/,<GRP>);
close(GRP);
if (! ($_[0] =~ /^\d*$/)) {
print "Error: A group ID should contain only numbers.\a\n";
exit;
}
elsif ( $_[0] < db_get(\%conf, 'MinUid')) {
print "Error: The group ID should be greater or equal to ".&FindUid.".\a\n";
exit;
}
elsif ((grep(/Gid\|$_[0]\D/,@recs)) or
(grep(/\:$_[0]\:/,@pwds)) or
(grep(/\:$_[0]\:/,@grps))) {
print "Error: The gid '$_[0]' is already in use\a\n";
exit;
}
else { return 1 };
}
#==============================================================================
# Test name for illegal characters
sub TestName {
if ( $_[0] =~ /^[a-z][a-z\-\_\d]*$/ ) {
return -1;
}
else {
print "The group name '$_[0]' contains illegal characters.\n";
print "The name should contain only lower-case letters, numbers, hyphens and\n";
print "underscores, and should start with a lower-case letter.\n\a";
return 0;
}
}
#==============================================================================
# Test for wildcards in the groupname. If any wildecards are found, the array
# @records is expanded with the groupnames that meet the conditions.
sub ExpandWildCard {
my $ctrec = 0;
foreach my $record (@records)
{
my @fld=split(/\|/,$record);
for (my $cnt=0; $cnt <= $#fld; ++$cnt) { for ($fld[$cnt]) { s/^\s+//; s/\s+$//; }}
if ($fld[0] =~ /\*|\?/) { # Does it contain the wildcards?
$fld[0] =~ s/\*/\.\*/g; # Replace * with .* to allow for grep.
$fld[0] =~ s/\?/\./g; # Replace ? with . to allow for grep.
open USRS, "</home/e-smith/db/accounts" or die "Can't open /home/e-smith/db/accounts: $!";
my @match = grep /^$fld[0]\=group\|/i, <USRS>;
close(USRS);
my $cu = 0;
foreach my $tst (@match) {
$tst =~ /\=/; $tst = $`;
for (my $cnt=1; $cnt <= $#fld; ++$cnt) { $tst = $tst." | ".$fld[$cnt]; };
if ($cu == 0 ) {
$records[$ctrec] = $tst;
$cu =1;
}
else {
push(@records, $tst);
}
}
}
++$ctrec;
}
}
#==============================================================================
# Print the pod text as a help screen
sub PrintPod {
my ($verbose, $message) = @_;
pod2usage(-verbose => $verbose, -message => $message, -exitval => 64);
}
#==============================================================================
=pod
=head1 NAME
B<lat-groups> - The lazy administrator's tool to create groups and to add members to it.
=head1 DESCRIPTION
Creates or deletes groups on Mitel's or SME Servers (5.x/6.x/7.x).
This tool is functionally equivalent to the 'groups' option in the server-manager, but can be run from the command line or called from an other script.
It allows you, for example, to add a large number of accounts to a group, or delete groups on a remote machine via an ssh console.
See F</usr/doc/lazy-admin-tools/example.groups> for the format of the input file.
=head1 SYNOPSIS
B<lat-groups> -a [-n] -c "group | descr. | gid | user1| user2"
B<lat-groups> -a [-n] -i /path/to/groups.list
B<lat-groups> -r [-f] -c "group | user1 | user2"
B<lat-groups> -d [-f] -c "group"
B<lat-groups> -d [-f] -i /path/to/groups.list
=head1 OPTIONS
The following options are supported:
=over 4
=item B<-a>, B<--add>
Add a group to the server, or add users to an existing group.
=item B<-c "Arguments">, B<--command-line="Aruments">
Take arguments from the command line.
See the 'Arguments' section below for the various arguments that are accepted.
=item B<-d>, B<--delete>
Delete a group from the server. Wildcards (* and ?) are accepted.
=item B<-f>, B<--force>
Don't prompt before deleting.
=item B<-h>, B<--help>
Extended help for this tool
=item B<-i FILE>, B<--input-file=FILE>
Use the information from F<FILE> to create or delete the group(s).
See F</usr/doc/lazy-admin-tools> for an example of an input file.
=item B<-n>, B<--no-admin>
Do not add 'admin' and 'www' as users to this group. Remove them if they are already member of this group.
Default behaviour on SME is to add both users to any group, thus limiting the number of groups on the server to 28.
Note, however, that SME is very persistent with this 'feature'. Each time you add or remove a user via the
server-manager, both 'admin' and 'www' are added again.
=item B<-r>, B<--remove-users>
Remove users from this group. Wildcards (* and ?) are accepted for the groupname.
=back
=head2 Arguments:
group* : Must contain only lower-case letters, numbers,
hyphens, periods and underscores, and should
start with a lower-case letter. Wildcards (* and ?)
can only be used to delete groups.
descr. : Free-text description of the group
gid : Group ID. If omitted, a suitable gid will be generated.
member(s) : Username of a member of the group. Must be an
existing account on the server.
* mandatory field
=head1 EXAMPLES
B<lat-groups -a -c "hogwarts | School of Witchcraft | | harry | hermione">
Creates group 'hogwarts' with users 'harry' and 'hermione'.
B<lat-groups -a -i /root/griffindor.list>
Creates the groups defined in /root/griffindor.list.
Refer to /usr/doc/lazy-admin-tools/example.groups for an example of an input file.
B<lat-groups -a -n -i /root/griffindor.list>
Creates the groups defined in /root/griffindor.list.
The users 'admin' and 'www' are *not* added to the group.
B<lat-groups -d -f -c "class*">
Deletes all groups whose name start with 'class'.
All groups are deleted without prompting (-f).
B<lat-groups -r -f -c " * | admin | www">
Removes users 'admin' and 'www' from all groups on the system.
Don't prompt before removing.
B<lat-groups -a -c "quidditch | Different ball game | 7005">
Creates group 'quidditch' with group ID 7005.
=head1 SEE ALSO
lat-users(8), lat-pseudonyms(8), lat-ibays(8), lat-quota(8), lat-domains(8), lat-hosts(8), lat-procmail(8), lat-pptp(8), lat-dump(8)
=head1 VERSION
Version 0.9.0 (2004-09-08). The latest version is hosted at B<http://www.contribs.org/contribs/mblotwijk/>
=head1 COPYRIGHT
(c)2003-2004, Altiplano bvba (B<http://www.altiplano.be>). Released under the terms of the GNU license.
=head1 BUGS
Please report bugs to <Bugs@Altiplano.Be>
=cut
#==============================================================================