summaryrefslogtreecommitdiff
path: root/groupmanage
diff options
context:
space:
mode:
authorian <ian>1999-11-09 20:47:46 +0000
committerian <ian>1999-11-09 20:47:46 +0000
commitd38b93ab413ea961a8d6a3a762d6e28d3bac8afc (patch)
tree281420944b44c6022b99a41b3115a26859a1fc66 /groupmanage
parent8d9c58663412f651132b7f75ca3a49514cb1fd4d (diff)
downloaduserv-utils-d38b93ab413ea961a8d6a3a762d6e28d3bac8afc.tar.gz
As found on chiark - checked in.
Diffstat (limited to 'groupmanage')
-rwxr-xr-xgroupmanage/groupmanage333
-rw-r--r--groupmanage/groupmanage.conf6
-rw-r--r--groupmanage/services10
3 files changed, 349 insertions, 0 deletions
diff --git a/groupmanage/groupmanage b/groupmanage/groupmanage
new file mode 100755
index 0000000..48e7077
--- /dev/null
+++ b/groupmanage/groupmanage
@@ -0,0 +1,333 @@
+#!/usr/bin/perl
+#
+# Reads /etc/grouplist, in form
+# group:description:owner:manager1,manager2,manager3:home-directory
+# (as many or few managers as you like)
+# Modifies /etc/grouplist by adding or removing managers &c,
+# and /etc/group by adding or removing members.
+
+# Copyright (C)1995-8 Ian Jackson <ijackson@chiark.greenend.org.uk>
+
+# This is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# It is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+sub usage {
+ &unlock;
+ &p_out;
+ print(<<END) || die "groupmanage: write usage: $!\n";
+groupmanage: $_[0]
+ usage:
+ groupmanage <groupname> [--info]
+ groupmanage <groupname> <action> [<action> ...]
+ groupmanage <groupname> --create [<action> <action> ...]
+ actions:
+ --clear
+ --add <username> <username> ...
+ --remove <username> <username> ...
+ --manager-clear
+ --manager-add <username> <username> ...
+ --manager-remove <username> <username> ...
+ --title <string>
+ --owner <username> [root only]
+END
+ exit(1);
+}
+
+@ARGV || &usage('too few arguments');
+
+if ($>) {
+ exec 'userv','root','groupmanage',@ARGV;
+ &quit("unable to execute userv to gain root privilege: $!");
+}
+
+chdir("/etc") || die "groupmanage: chdir /etc: $!\n";
+
+$groupname= shift(@ARGV);
+$groupname =~ y/\n//d;
+
+$groupname =~ m/^\w[-0-9A-Za-z]*$/ ||
+ &quit("first argument is invalid - must be group name");
+
+@ARGV || push(@ARGV,'--info');
+
+if ($ARGV[0] eq '--info') {
+ @ARGV == 1 || &usage('no arguments allowed after --info');
+ &p_out;
+ &load;
+ &checkexists;
+ &display;
+ &p_out;
+ exit(0);
+}
+
+$callinguser= exists $ENV{'USERV_UID'} ? $ENV{'USERV_UID'} : $<;
+
+%opt= ('user-create','0',
+ 'user-create-minunameu','5',
+ 'user-create-min','10000',
+ 'user-create-max','19999',
+ 'user-create-nameintitle','0',
+ 'user-create-maxperu','5');
+%ovalid= ('user-create','boolean',
+ 'user-create-minunameu','number',
+ 'user-create-min','number',
+ 'user-create-max','number',
+ 'user-create-nameintitle','boolean',
+ 'user-create-maxperu','number');
+
+sub ov_boolean {
+ $cov= $_ eq 'yes' ? 1 :
+ $_ eq 'no' ? 0 :
+ &quit("groupmanage.conf:$.: bad boolean value");
+}
+
+sub ov_number {
+ m/^[0-9]{1,10}$/ || &quit("groupmanage.conf:$.: bad numerical value");
+}
+
+open(GMC,"groupmanage.conf") || &quit("read groupmanage.conf: $!");
+while (<GMC>) {
+ next if m/^\#/ || !m/\S/;
+ s/\s*\n$//;
+ s/^\s*([-0-9a-z]+)\s*// || &quit("groupmanage.conf:$.: bad option format");
+ $co= $1;
+ defined($opt{$co}) || &quit("groupmanage.conf:$.: unknown option $co");
+ $cov= $_;
+ $ovf= 'ov_'.$ovalid{$co};
+ &$ovf;
+ $opt{$co}= $cov;
+}
+close(GMC);
+
+sub naming {
+ $callinguser || return;
+ &p_out;
+ print(STDERR <<END) || &quit("write err re name: $!");
+groupmanage: groups you create must be named after you ...
+ <usernamepart>-<identifier>
+ You must quote at least $opt{'user-create-minunameu'} chars of your username $createby
+ (or all of it if it is shorter).
+END
+ exit(1);
+}
+
+if ($ARGV[0] eq '--create') {
+ $opt{'user-create'} || !$callinguser ||
+ &quit("group creation by users disabled by administrator");
+ length($groupname) <= 8 || &quit("group names must be 8 chars or fewer");
+ $groupname =~ m/^([-0-9A-Za-z]+)-([0-9a-z]+)$/ || &naming;
+ $upart= $1;
+ $idpart= $2;
+ $!=0; (@pw= getpwuid($callinguser))
+ || &quit("cannot get your passwd entry: $!");
+ $createby= $pw[0];
+ $upart eq $createby ||
+ (length($upart) >= $opt{'user-create-minunameu'} &&
+ substr($createby,0,length($upart)) eq $upart)
+ || &naming;
+ $create= 1;
+ shift(@ARGV);
+}
+
+&lock;
+&load;
+
+if ($create) {
+ $bythisowner < $opt{'user-create-maxperu'} ||
+ &quit("you already have $bythisowner group(s)");
+ $groupfileix==-1 || &quit("group already exists, cannot create it");
+ $grouplistix==-1 || &quit("group is already in grouplist, cannot create it");
+ for ($gid= $opt{'user-create-min'};
+ $gid < $opt{'user-create-max'} && defined(getgrgid($gid));
+ $gid++) { }
+ $gid <= $opt{'user-create-max'} || &quit("out of gids to use, contact admin");
+ $password=''; @members=($createby);
+ $description= "${createby}'s -- user-defined, no title";
+ $owner= $createby; @managers=(); @members= ($createby);
+ $groupfileix=$#groupfile+1;
+ $grouplistix=$#grouplist+1;
+ &p("created group $groupname");
+} else {
+ &checkexists;
+ &p("modifying group $groupname");
+}
+
+&weare($owner) || grep(&weare($_),@managers) || !$callinguser ||
+ &quit("you may not manage $groupname");
+
+$action= 'none';
+while (@ARGV) {
+ $_= shift(@ARGV);
+ if (m/^--(add|remove)$/) {
+ $action= $1; $clist= 'members'; $what= 'member';
+ } elsif (m/^--owner$/) {
+ !$callinguser || &quit("only root may change owner");
+ @ARGV || &usage("no username owner after --owner");
+ $owner= shift(@ARGV);
+ &p("owner set to $owner");
+ } elsif (m/^--manager-(add|remove)$/) {
+ $action= $1; $clist= 'managers'; $what= 'manager';
+ } elsif (m/^--clear$/) {
+ &p('cleared list of members');
+ @members=(); $action='none'; $memc++;
+ } elsif (m/^--manager-clear$/) {
+ &p('cleared list of managers');
+ @managers=(); $action='none';
+ } elsif (m/^--title$/) {
+ &weare($owner) || !$callinguser ||
+ &quit("only group's owner ($owner) may change title");
+ @ARGV || &usage("no title after --title");
+ $_= shift(@ARGV); y/\020-\176//cd; y/:\\//d;
+ if ($opt{'user-create-nameintitle'} &&
+ $gid >= $opt{'user-create-min'} && $gid <= $opt{'user-create-max'}) {
+ $_= "${owner}'s -- $_";
+ }
+ $description= $_;
+ &p("title set to $description");
+ } elsif (m/^-/) {
+ &usage("unknown option $_");
+ } elsif (m/^\w[-0-9A-Za-z]*$/) {
+ y/\n//d;
+ $chgu=$_;
+ (@pw= getpwnam($chgu)) || &quit("username $chgu does not exist");
+ eval "\@l = \@$clist; 1" || &quit("internal error: $@");
+ $already= grep($_ eq $chgu, @l);
+ if ($action eq 'add') {
+ if ($already) {
+ &p("$chgu already $what");
+ } else {
+ &p("added $what $chgu");
+ push(@l,$chgu);
+ $memc+= ($clist eq 'members');
+ }
+ } elsif ($action eq 'remove') {
+ if ($already) {
+ &p("removed $what $chgu");
+ @l= grep($_ ne $chgu, @l);
+ $memc+= ($clist eq 'members');
+ } else {
+ &p("$chgu is already not $what");
+ }
+ } else {
+ &usage("username found but no action to take for them");
+ }
+ eval "\@$clist = \@l; 1" || &quit("internal error: $@");
+ } else {
+ &usage("bad username or option $_");
+ }
+}
+&p("nb: a change to group membership only takes effect at the user's next login")
+ if $memc;
+$groupfile[$groupfileix]=
+ "$groupname:$password:$gid:".join(',',@members)."\n";
+$grouplist[$grouplistix]=
+ "$groupname:$description:$owner:".join(',',@managers).":$homedir\n";
+&save('group',@groupfile);
+&save('grouplist',@grouplist);
+unlink('gtmp') || &quit("unlock group (remove gtmp): $!");
+&p_out;
+exit(0);
+
+sub load {
+ open(GF,"< group") || &quit("read group: $!");
+ @groupfile=<GF>; close(GF);
+ $groupfileix=-1;
+ for ($i=0; $i<=$#groupfile; $i++) {
+ $_= $groupfile[$i]; s/\n$//;
+ next if m/^\#/;
+ m/^(\w[-0-9A-Za-z]*):([^:]*):(\d+):([-0-9A-Za-z,]*)$/ ||
+ &quit("bad entry in group: $_");
+ $gname2gid{$1}=$3;
+ next unless $1 eq $groupname;
+ $groupfileix<0 || &quit("duplicate entries in group");
+ $groupfileix= $i;
+ $password= $2;
+ $gid= $3;
+ @members= split(/,/,$4);
+ }
+ open(GL,"< grouplist") || &quit("read grouplist: $!");
+ @grouplist=<GL>; close(GL);
+ $grouplistix=-1;
+ for ($i=0; $i<=$#grouplist; $i++) {
+ $_= $grouplist[$i]; s/\n$//;
+ next if m/^\#/;
+ m/^(\w[-0-9A-Za-z]*):([^:]*):(\w[-0-9A-Za-z]*):([-0-9A-Za-z,]*):([^:]*)$/ ||
+ &quit("bad entry in grouplist: $_");
+ $bythisowner++ if ($create && $3 eq $createby &&
+ $gname2gid{$1} >= $opt{'user-create-min'} &&
+ $gname2gid{$1} <= $opt{'user-create-max'});
+ next unless $1 eq $groupname;
+ $grouplistix<0 || &quit("duplicate entries in grouplist");
+ $grouplistix= $i;
+ $description= $2;
+ $owner= $3;
+ $homedir= $5;
+ @managers= split(/,/,$4);
+ }
+}
+
+sub checkexists {
+ $grouplistix>=0 || &quit("no entry in grouplist for $groupname");
+ $groupfileix>=0 || &quit("no entry in group for $groupname");
+}
+
+sub weare {
+ return 0 if $_[0] eq '';
+ @pw= getpwnam($_[0]);
+ return @pw && $pw[2] == $callinguser ? 1 : 0;
+}
+
+sub save {
+ $filename= shift(@_);
+ unlink("$filename~");
+ open(DUMP,"> $filename.new") || &quit("create new $filename: $!");
+ print(DUMP @_) || &quit("write new $filename: $!");
+ close(DUMP) || &quit("close new $filename: $!");
+ link("$filename","$filename~") || &quit("create backup $filename: $!");
+ rename("$filename.new","$filename") || &quit("install new $filename: $!");
+}
+
+sub quit {
+ &unlock;
+ &p_out;
+ die "groupmanage: @_\n";
+}
+
+sub lock {
+ link('group','gtmp') || &quit("create gtmp: $!");
+ $locked++;
+}
+
+sub unlock {
+ return unless $locked;
+ $locked--;
+ unlink('gtmp') || warn("unlock group file (remove gtmp): $!\n");
+}
+
+sub display {
+ print(<<END) || &quit("write to stdout: $!\n");
+group $groupname
+gid $gid
+description $description
+owner $owner
+managers @managers
+members @members
+homedir $homedir
+END
+}
+
+sub p_out {
+ print(STDOUT "$stdout_string") || &quit("write to stdout: $!\n");
+ $stdout_string= '';
+}
+
+sub p {
+ $stdout_string.= $_[0]."\n";
+}
diff --git a/groupmanage/groupmanage.conf b/groupmanage/groupmanage.conf
new file mode 100644
index 0000000..07bfc8f
--- /dev/null
+++ b/groupmanage/groupmanage.conf
@@ -0,0 +1,6 @@
+user-create yes
+user-create-minunameu 4
+user-create-min 5000
+user-create-max 8999
+user-create-nameintitle yes
+user-create-maxperu 5
diff --git a/groupmanage/services b/groupmanage/services
new file mode 100644
index 0000000..ad40a21
--- /dev/null
+++ b/groupmanage/services
@@ -0,0 +1,10 @@
+#
+if ( grep calling-user-shell /etc/shells
+ & glob service-user root
+ )
+ reset
+ set-environment
+ no-suppress-args
+ no-disconnect-hup
+ execute groupmanage
+fi