home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
- #
- # addgroup: a utility to add groups to the system
- # $Id: addgroup,v 0.10 1995/03/02 03:24:38 tedhajek Exp $
-
- #
- # Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu>
- # General scheme of the program adapted by the debian 'adduser'
- # program by Ian A. Murdock <imurdock@gnu.ai.mit.edu>.
- #
- # This program 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 of the License, or
- # (at your option) any later version.
- #
- # This program 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.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- #
- # NOTE: addgroup should be used to add system, maintenance and
- # project groups to the system.
- #
- # By default, the debian 'adduser' program creates
- # a group for each created user; this group has the same
- # ID number as the associated user.
- #
- # Therefore, we shouldn't create any groups with GID equal
- # to or greater than the lowest UID used by adduser.
- # This is given in the file /etc/adduser.conf in an entry
- # such as "FIRST_UID=1000"
- #
- # Furthermore, the first 99 GIDs are reserved for the base
- # system maintainer. Therefore, we should add groups with
- # GIDs greater than or equal to 100.
- #
- # If there is no available GID under FIRST_UID, exit with
- # a suitable error message.
- #
- ##
- ## TODO
- ##
- #
- # - allow users belonging to group to be specified on command line?
-
-
- # are we debugging?
- $debugging = 0;
-
- ##
- ## need to trap signals 1 2 3 and 15 here so user can't kill us
- ## when things are in some half-baked state.
- ##
-
- # Set up some important things:
- $GROUP = "/etc/group"; # the group file
- $GBACK = "/etc/group~"; # the backup group file
- $GLOCK = "/etc/gtmp"; # the lock file
- # I don't know if this is standard,
- # but it should be :-)
- # I'll work out a better locking scheme
- # later.
- $DEFAULTS = "/etc/adduser.conf";
- $default_first_uid = 1000; # value to use if we can't find one
- # specified in the adduser.conf file
- $MIN_GID = 100; # leave some room for system stuff
-
- ##
- ## check if certain conditions are met before we start
- ## plodding around within the group file.
- ##
-
- # we must be root.
- if ($> != 0) {
- print "$0: only root may add groups to the system.\n";
- exit 1;
- }
- # the user must specify a group name to add
- $group_name = shift(@ARGV);
- print STDOUT "$group_name\n" if $debugging;
- if (! $group_name) {
- print "$0: you must specify a group name to be added.\n";
- print "For example, '$0 junk-maintainers'.\n";
- exit 1;
- }
- # check if the group to be added already exists
- if (&group_exists($group_name)) {
- print "$0: the group you specified already exists.\n";
- exit 1;
- }
- # check if the group file is locked by some other process
- if (-f $GLOCK) {
- print "$0: $GROUP is locked. Try again later.\n";
- exit 1;
- }
-
- ##
- ## lock the group file
- ##
- link $GROUP, $GLOCK;
-
- # read the file of defaults.
- $first_uid = &get_first_uid($DEFAULTS, $default_first_uid);
-
- # suck the existing GIDs into an array
- @current_gids = &get_current_gids;
- # sort 'dem GIDs
- @sorted_gids = sort {$a <=> $b} @current_gids;
- # find the first available GID
- $last_one = shift(@sorted_gids);
- while ($this_one = shift(@sorted_gids)) {
- if ($this_one <= $MIN_GID) {
- $last_one = $this_one; # advance if we're under $MIN_GID
- next;
- }
- if ($this_one > $last_one + 1) {
- $lowest_available = $last_one + 1;
- last;
- } else {
- $last_one = $this_one;
- }
- }
- # if we haven't yet set $lowest_available, there's no hole.
- $lowest_available = ($last_one + 1) if (! $lowest_available);
- # make sure we're at the minimum.
- $lowest_available = $MIN_GID if ($lowest_available < $MIN_GID);
-
- # make sure that we're below the ceiling
- if ($lowest_available >= $first_uid) {
- print "$0: no GID available beneath first normal user's ID.\n";
- exit 1;
- }
-
- # save the original group file
- open (GBACK, ">$GBACK") || die "open: $!";
- open (GROUP, "$GROUP") || die "open: $!";
- while (<GROUP>) {
- print GBACK;
- }
- close GROUP;
- close GBACK;
-
- # write the new entry at the appropriate place in the group file
- open (GROUP, ">$GROUP") || die "open: $!";
- open (GBACK, "$GBACK") || die "open: $!";
- $added_new_one = 0;
- while($line = <GBACK>) {
- chop $line;
- ($name, $passwd, $gid, $members) = split(/:/, $line);
- if ($gid < $lowest_available || $added_new_one) {
- print GROUP $line, "\n";
- print STDOUT "GID: $gid\n" if $debugging;
- } else { # we haven't added the new one yet
- print GROUP "${group_name}::${lowest_available}:\n";
- $added_new_one = 1;
- print STDOUT "Just added new one\n" if $debugging;
- print GROUP $line, "\n";
- print STDOUT "GID: $gid\n" if $debugging;
- }
- }
- print GROUP "${group_name}::${lowest_available}:\n" if (! $added_new_one);
-
- close GROUP;
- close GBACK;
-
- # we're done! Unlock the group file
- unlink $GLOCK;
- print "done.\n";
- exit 0;
-
- ###################################################
- #=================================================#
- ###################################################
-
- ###
- ### Subroutines
- ###
-
- ############################
- # get_current_gids
- ############################
- # iterate through the group file; return an array
- # containing all the GIDs
- sub get_current_gids {
- local (@gids);
- local ($name, $passwd, $gid, $members); # the return values of "getgrent";
-
- setgrent;
- while (($name, $passwd, $gid, $members) = getgrent) {
- push @gids, $gid;
- }
- endgrent;
-
- return @gids;
- }
-
- ############################
- # get_first_uid
- ############################
- # parse the defaults file for the first user UID number.
- # if the default file or entry doesn't exist, return the
- # SYSTEM default value given in 'adduser'.
- sub get_first_uid {
- local($conf_file, $default) = @_;
- local($current_line, $tag, $uid);
-
- # if there's not a config file, return the default.
- print "Couldn't find $conf_file\n" if ($debugging && (! -f $conf_file));
- return $default if (! -f $conf_file);
-
- open (CONF, $conf_file) || die "open: $!";
- while ($current_line = <CONF>) {
- chop $current_line;
- if ($current_line =~ /^FIRST_UID=(\d+)$/) {
- $uid = $1;
- last;
- }
- }
- close (CONF);
-
- print "Got UID = $uid from $conf_file\n" if ($uid && $debugging);
- return $uid if ($uid);
- print "Using default UID = $default\n" if $debugging;
- return $default;
- }
-
-
-
- #############################
- # group_exists
- #############################
- # takes a group name as an argument. If the group already exists,
- # return 1. If it doesn't, return 0.
- sub group_exists {
- local ($group_name) = @_;
- local ($exists); # does group exist?
- local ($name, $passwd, $gid, $members); # the return values of "getgrent";
-
- $exists = 0;
- # reset the group lookup function
- setgrent;
- # iterate through the group file. If the group exists, return 1.
- while (($name, $passwd, $gid, $members) = getgrent) {
- if ($name eq $group_name) {
- $exists = 1;
- last;
- }
- }
- # close the group file
- endgrent;
-
- return $exists;
- }
-
-
-
-
-
-