diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 05:55:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 05:55:27 +0000 |
commit | 32e0ba8ebdadc47ac1a0da8d9a9668ff21909e4f (patch) | |
tree | ebaa5eacafe874b431d69e52f0f73c013c3017ae /examples/adduser.local | |
parent | Initial commit. (diff) | |
download | adduser-upstream/3.118+deb11u1.tar.xz adduser-upstream/3.118+deb11u1.zip |
Adding upstream version 3.118+deb11u1.upstream/3.118+deb11u1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'examples/adduser.local')
-rwxr-xr-x | examples/adduser.local | 849 |
1 files changed, 849 insertions, 0 deletions
diff --git a/examples/adduser.local b/examples/adduser.local new file mode 100755 index 0000000..7861200 --- /dev/null +++ b/examples/adduser.local @@ -0,0 +1,849 @@ +#!/usr/bin/perl -w + +######################################################################### +# # +# ADDUSER Local System Additions v4.9 # +# Copyright (C) 1999-2013, John Zaitseff # +# # +######################################################################### + +# Author: John Zaitseff <J.Zaitseff@zap.org.au> +# Date: 21st June, 2013 +# Version: 4.9 + +# This program, once installed as /usr/local/sbin/adduser.local, is auto- +# matically called by the adduser(8) system program on a Debian system. +# This script completes the creation of a user account in a system- +# dependent way. +# +# This script is automatically called by adduser with arguments "USERNAME +# UID GID HOMEDIR". See adduser(8) for more details. In addition, this +# script may be called manually; run "perldoc adduser.local" for more +# details. + + +# This program, including associated files, is free software. You may +# distribute 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., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +######################################################################### +# Configuration parameters and default values + +use strict; # Enforce better programming habits + +use locale; # Allow locale-specific sorting, etc. +use utf8; # This script may use the UTF-8 character set +use open ":locale"; # Use locale for standard input/output + +use Getopt::Long; # Parse command line options +use Pod::Usage; # Display command line usage + + +(our $O = $0) =~ s,^.*/,,; # Script name (without path) +our $version = "4.9"; # Script version + +our $copyright = # Copyright information +"$O v$version: adduser(8) local system additions\n" . +"Copyright (C) 1999-2013, John Zaitseff.\n"; + +our @adduser = ('/usr/sbin/adduser', '--quiet'); # adduser(8) +our @chown = ('/bin/chown', '-h'); # chown(1) +our @install = ('/usr/bin/install', '-p'); # install(1) + +our $procmounts = '/proc/mounts'; # List of current mounts + +# These default values are extensively documented in adduser.local.conf. + +our $d_conffile = '/etc/adduser.local.conf'; # Configuration file location +our $d_skelother = '/etc/skel.other'; # Location of skeleton files +our $d_dirmode = '2755'; # Octal mode for directories +our $d_filemode = '0644'; # Octal mode for files + +our $d_user = ''; # Default service user name +our $d_group = ''; # Default service group name +our $d_addtogroup = 'false'; # Default for addtogroup variable +our $d_homedir = ''; # Default home directory +our $d_subdir = ''; # Default subdirectory +our $d_althome = 'false'; # Default for use alternate home directory +our $d_mounted = 'false'; # Default for checking if mounted +our $d_mkdir = 'false'; # Default for creating directory +our $d_chgrpdir = 'false'; # Default for chgrpdir variable +our $d_mklink = 'false'; # Default for creating symbolic link +our $d_linkname = ''; # Default for symbolic link name +our $d_skelfile = ''; # Default for skeleton file +our $d_chgrpskel = 'false'; # Default for chgrpskel variable + +# Strings appearing in the configuration file + +our $s_skelother = 'skelother'; +our $s_dirmode = 'dirmode'; +our $s_filemode = 'filemode'; + +our $s_service = 'service'; + +our $s_user = 'user'; +our $s_group = 'group'; +our $s_addtogroup = 'addtogroup'; +our $s_homedir = 'homedir'; +our $s_subdir = 'subdir'; +our $s_althome = 'althome'; +our $s_mounted = 'mounted'; +our $s_mkdir = 'mkdir'; +our $s_chgrpdir = 'chgrpdir'; +our $s_mklink = 'mklink'; +our $s_linkname = 'linkname'; +our $s_skelfile = 'skelfile'; +our $s_chgrpskel = 'chgrpskel'; + +our @s_false = ('false', 'f', 'no', 'n', '0'); +our @s_true = ('true', 't', 'yes', 'y', '1'); + +# Strings internal to this program (as used by the %cv hash) + +our $s_svcuid = '.svcuid'; # Storage for UID of service's user name +our $s_svcgid = '.svcgid'; # GID of service's user name or group name +our $s_actualdir = '.actualdir'; # Actual dir: homedir + subdir + username +our $s_actuallink = '.actuallink'; # Actual sym link: user homedir + linkname +our $s_actualsrcf = '.actualsrcf'; # Actual source file: skelother + skelfile +our $s_actualdstf = '.actualdstf'; # Actual dest file: actualdir + skelfile + +our $s_addtogroupB = '.addtogroupB'; # Boolean versions of variables +our $s_althomeB = '.althomeB'; +our $s_mountedB = '.mountedB'; +our $s_mkdirB = '.mkdirB'; +our $s_chgrpdirB = '.chgrpdirB'; +our $s_mklinkB = '.mklinkB'; +our $s_chgrpskelB = '.chgrpskelB'; + +# Function prototypes + +sub chkbool($$$$); +sub lchown(@); +sub showusage(); +sub showversion(); +sub showcmdlerr(@); + + +######################################################################### +# Initialise global variables + +our $conffile = $d_conffile; # Default configuration file +our $verbose = 1; # Be verbose by default +our $dryrun = 0; # NOT a dry run by default + +our @services = (); # No services to install by default + +# %cv is a hash for all configuration variables read in from the +# configuration file. Global variables are represented by their strings, +# eg, $cv{"skelother"}. Service-specific variables are represented by the +# service string value, a comma, then their string, eg, $cv{"www","user"}. +# The %cl hash plays a similar role, but contains the line number of the +# configuration. + +our (%cv, %cl); + +$cv{$s_skelother} = $d_skelother; $cl{$s_skelother} = 0; +$cv{$s_dirmode} = $d_dirmode; $cl{$s_dirmode} = 0; +$cv{$s_filemode} = $d_filemode; $cl{$s_filemode} = 0; + +# For safety's sake, initialise the PATH environment variable + +$ENV{PATH} = '/usr/sbin:/usr/bin:/sbin:/bin'; + +# Declare some global variables + +our $username; # Username for which adduser.local was called +our $uid; # User's UID +our $gid; # User's GID +our $homedir; # User's home directory + + +######################################################################### +# Process command-line arguments + +our $opt_help; +our $opt_version; + +Getopt::Long::Configure("bundling"); + +GetOptions('help|h|?' => \$opt_help, + 'version|V' => \$opt_version, + 'conf=s' => \$conffile, + 'dry-run|n!' => \$dryrun, + 'verbose|v!' => \$verbose, + 'quiet|q' => sub { $verbose = 0; }, + ) + or showcmdlerr(); + +showusage() if $opt_help; +showversion() if $opt_version; + + +######################################################################### +# Process additional command-line parameters: USERNAME [UID GID HOMEDIR] + +if ($#ARGV < 0) { showcmdlerr("$O: Missing USERNAME parameter"); } +if ($#ARGV > 3) { showcmdlerr("$O: Too many command-line parameters"); } + +# Include some sanity checking. These checks are not particularly +# rigorous, as root can do anything anyway... It is meant to stop silly +# mistakes, not to stop thinking. In any case, this script SHOULD only +# be called from adduser(8)... + +die "$O: Only root can execute this program\n" if ($> != 0) and (! $dryrun); + +if ($#ARGV == 0) { + # Only a single parameter: USERNAME + + $username = $ARGV[0]; + + (my $t_name, undef, $uid, $gid, undef, undef, undef, $homedir) + = getpwnam($username); + + die "$O: No such user: $username\n" if ! defined($t_name); + +} elsif ($#ARGV == 3) { + # Four parameters: USERNAME UID GID HOMEDIR + + $username = $ARGV[0]; + $uid = $ARGV[1]; + $gid = $ARGV[2]; + $homedir = $ARGV[3]; + + $homedir =~ s,/$,,; # Remove trailing '/' if present + (my $t_name, undef, my $t_uid, my $t_gid) = getpwnam($username); + + die "$O: No such user: $username\n" if ! defined($t_name); + die "$O: No such UID: $uid\n" if ! defined(getpwuid($uid)); + die "$O: No such GID: $gid\n" if ! defined(getgrgid($gid)); + die "$O: UID of user $username not the same as $uid\n" if $t_uid != $uid; + die "$O: GID of user $username not the same as $gid\n" if $t_gid != $gid; + die "$O: Directory does not exist: $homedir\n" if ! -d $homedir; + +} else { + showcmdlerr("$O: Missing UID, GID and/or HOMEDIR parameters"); +} + + +######################################################################### +# Process the configuration file + +if (! -r $conffile) { + warn "$O: Cannot read configuration file $conffile:\n"; + warn "$O: $conffile: $!\n"; + + exit(0); +} + +print "Processing configuration file $conffile\n" if $verbose; + +open(CONFFILE, $conffile) or die "$O: $conffile: $!\n"; + +while (<CONFFILE>) { + my ($var, $svc, $val); + + chomp; + + # Skip comments and blank lines + next if /^\s*#/ or /^\s*$/; + + # Try matching a global variable with or without quotes + if ((($var, $val) = /^\s*(\w+)\s*=\s*(.*)$/) == 2) { + + # Remove trailing spaces and surrounding quotes + # (Technically, doing it this way is slightly sloppy) + $val =~ s/^(.*?)\s*$/$1/; + $val =~ s/^\"(.*)\"$/$1/; + $val =~ s/^\'(.*)\'$/$1/; + + # Process the global variable + if ($var eq $s_service) { + + # Special global configuration variable "service" + my $svc = $val; + + if (grep($_ eq $svc, @services)) { + warn "$O: Service \"$val\" redefined at $conffile:$.\n"; + next; + } + + push @services, $val; + + # Set up default values + + $cv{$svc,$s_user} = $d_user; + $cv{$svc,$s_group} = $d_group; + $cv{$svc,$s_addtogroup} = $d_addtogroup; + $cv{$svc,$s_homedir} = $d_homedir; + $cv{$svc,$s_subdir} = $d_subdir; + $cv{$svc,$s_althome} = $d_althome; + $cv{$svc,$s_mounted} = $d_mounted; + $cv{$svc,$s_mkdir} = $d_mkdir; + $cv{$svc,$s_chgrpdir} = $d_chgrpdir; + $cv{$svc,$s_mklink} = $d_mklink; + $cv{$svc,$s_linkname} = $d_linkname; + $cv{$svc,$s_skelfile} = $d_skelfile; + $cv{$svc,$s_chgrpskel} = $d_chgrpskel; + + $cl{$svc,$s_user} = 0; + $cl{$svc,$s_group} = 0; + $cl{$svc,$s_addtogroup} = 0; + $cl{$svc,$s_homedir} = 0; + $cl{$svc,$s_subdir} = 0; + $cl{$svc,$s_althome} = 0; + $cl{$svc,$s_mounted} = 0; + $cl{$svc,$s_mkdir} = 0; + $cl{$svc,$s_chgrpdir} = 0; + $cl{$svc,$s_mklink} = 0; + $cl{$svc,$s_linkname} = 0; + $cl{$svc,$s_skelfile} = 0; + $cl{$svc,$s_chgrpskel} = 0; + } + else { + # Ordinary global variable + + if (! defined($cv{$var})) { + warn "$O: Unknown global variable \"$var\" at $conffile:$.\n"; + next; + } + + $cv{$var} = $val; + $cl{$var} = $.; + } + } + + # Try matching a service variable with or without quotes + elsif ((($var, $svc, $val) = /^\s*(\w+)\s*\[\s*(\w+)\s*\]\s*=\s*(.*)$/) == 3) { + + # Remove trailing spaces and surrounding quotes + $val =~ s/^(.*?)\s*$/$1/; + $val =~ s/^\"(.*)\"$/$1/; + $val =~ s/^\'(.*)\'$/$1/; + + if (! grep($_ eq $svc, @services)) { + warn "$O: Undefined service \"$svc\" at $conffile:$.\n"; + next; + } + if (! defined($cv{$svc,$var})) { + warn "$O: Unknown service variable \"$var\" at $conffile:$.\n"; + next; + } + + $cv{$svc,$var} = $val; + $cl{$svc,$var} = $.; + } + + # Otherwise, it is an error in the configuration file + else { + warn "$O: Could not parse line at $conffile:$.\n"; + next; + } +} + +close(CONFFILE) or die "$O: $conffile: $!\n"; + + +######################################################################### +# Global variables sanity checking +{ + my $t; + + # Check "skelother" + + if (! -d $cv{$s_skelother}) { + warn "$O: Directory $cv{$s_skelother} does not exist\n"; + } + + # Check "dirmode" + + $t = $cv{$s_dirmode}; + if (($t !~ /^[01234567]{1,4}$/) or (oct($t) == 0)) { + warn "$O: Illegal value \"$t\" at $conffile:$cl{$s_dirmode}\n"; + warn "$O: Global variable \"$s_dirmode\" set to $d_dirmode\n"; + $cv{$s_dirmode} = $d_dirmode; + } + + # Check "filemode" + + $t = $cv{$s_filemode}; + if (($t !~ /^[01234567]{1,4}$/) or (oct($t) == 0)) { + warn "$O: Illegal value \"$t\" at $conffile:$cl{$s_filemode}\n"; + warn "$O: Global variable \"$s_filemode\" set to $d_filemode\n"; + $cv{$s_filemode} = $d_filemode; + } +} + + +######################################################################### +# Actually perform what is required, with appropriate error checking + +foreach my $svc (@services) { + my ($t_user, $t_group, $t_homedir); + + print "Processing service \"$svc\"\n" if $verbose; + + # Check validity of all boolean variables and convert them to true bools + + chkbool($svc, $s_addtogroup, $s_addtogroupB, $d_addtogroup); + chkbool($svc, $s_althome, $s_althomeB, $d_althome); + chkbool($svc, $s_mounted, $s_mountedB, $d_mounted); + chkbool($svc, $s_mkdir, $s_mkdirB, $d_mkdir); + chkbool($svc, $s_chgrpdir, $s_chgrpdirB, $d_chgrpdir); + chkbool($svc, $s_mklink, $s_mklinkB, $d_mklink); + chkbool($svc, $s_chgrpskel, $s_chgrpskelB, $d_chgrpskel); + + # Process the "user" configuration variable + + if ($cv{$svc,$s_user} ne '') { + # Retrieve information about the specified service's user name + + (my $t_user, undef, $cv{$svc,$s_svcuid}, $cv{$svc,$s_svcgid}, + undef, undef, undef, my $t_homedir) = getpwnam($cv{$svc,$s_user}); + + if (! defined($t_user)) { + warn "$O: Illegal user name \"$cv{$svc,$s_user}\" at $conffile:$cl{$svc,$s_user}\n"; + } else { + $cv{$svc,$s_user} = $t_user; + } + + # Only set home directory information if not specified by user + if ($cv{$svc,$s_homedir} eq '') { + if ($cv{$svc,$s_althomeB}) { + $cv{$svc,$s_homedir} = $homedir; # From command line + } else { + $cv{$svc,$s_homedir} = $t_homedir; # From service's home + } + } + + # If the group parameter is not specified, get the appropriate info + # from the user information + if ($cv{$svc,$s_svcgid} and ($cv{$svc,$s_group} eq '')) { + ($cv{$svc,$s_group}) = getgrgid($cv{$svc,$s_svcgid}); + } + } + + # Process the "group" configuration variable + + if ($cv{$svc,$s_group} ne '') { + # Retrieve info about the group. Yes, it may have been done + # above, but specifying "group" can be done without specifying + # "user". In addition, a different group can be specified from + # that used by "user". + + ($t_group, undef, $cv{$svc,$s_svcgid}) = getgrnam($cv{$svc,$s_group}); + + if (! defined($t_group)) { + warn "$O: Illegal group name \"$cv{$svc,$s_group}\" at $conffile:$cl{$svc,$s_group}\n"; + + $cv{$svc,$s_addtogroup} = 'false'; $cv{$svc,$s_addtogroupB} = 0; + $cv{$svc,$s_chgrpdir} = 'false'; $cv{$svc,$s_chgrpdirB} = 0; + $cv{$svc,$s_chgrpskel} = 'false'; $cv{$svc,$s_chgrpskelB} = 0; + } + else { + $cv{$svc,$s_group} = $t_group; + } + } + + # Process the "addtogroup" configuration variable + + if ($cv{$svc,$s_addtogroupB} and ($cv{$svc,$s_group} ne '')) { + + my $t = $cv{$svc,$s_group}; + (my $t_group, undef, my $t_gid, my $t_members) = getgrnam $t; + + # Check if the user is already a member of that group + + if (($t_gid == $gid) or grep($_ eq $username, split(' ', $t_members))) { + print " User \"$username\" already in group \"$t\"\n" + if $verbose; + } else { + print " Adding user \"$username\" to group \"$t\"\n" + if $verbose; + system(@adduser, $username, $t) if ! $dryrun; + } + } + + # Process the "mounted" configuration variable + + $cv{$svc,$s_homedir} =~ s,/$,,; # Remove trailing / on homedir + $cv{$svc,$s_subdir} =~ s,^/,,; # Remove leading / on subdir + $cv{$svc,$s_subdir} =~ s,/$,,; # Remove trailing / on subdir + + if (($cv{$svc,$s_homedir} ne '') and $cv{$svc,$s_mountedB}) { + # Need to check for "mounted" before checking for the existence of + # of the service's home directory. + + if (! -r $procmounts) { + warn "$O: $procmounts: $!\n"; + } else { + my ($t_dev, $t_mntpoint, $t_type, $t_options); + my $ismounted = 0; + my $t_dir = $cv{$svc,$s_homedir} . '/'; + + # Open mounts table and process it + + open(MOUNTS, $procmounts) or die "$O: $procmounts: $!\n"; + while (<MOUNTS>) { + chomp; + ($t_dev, $t_mntpoint, $t_type, $t_options) = split; + if ($t_mntpoint !~ m,/$,) { $t_mntpoint .= '/'; } + + # Check if the service's home directory is mounted + # Skip "/" as that is always mounted + if (($t_mntpoint ne '/') and + (substr($t_dir, 0, length($t_mntpoint)) eq $t_mntpoint)) { + $ismounted = 1; + } + } + close(MOUNTS) or die "$O: $procmounts: $!\n"; + + if (! $ismounted) { + print " Directory $cv{$svc,$s_homedir} not mounted\n" + if $verbose; + $cv{$svc,$s_homedir} = ''; + } + } + } + + # Process the "homedir" and "subdir" configuration variables + + if ($cv{$svc,$s_homedir} ne '') { + if (! -d $cv{$svc,$s_homedir}) { + warn "$O: No such directory: $cv{$svc,$s_homedir}\n"; + $cv{$svc,$s_homedir} = ''; + } + elsif (($cv{$svc,$s_subdir} ne '') and (! $cv{$svc,$s_althomeB})) { + my $t = $cv{$svc,$s_homedir} . '/' . $cv{$svc,$s_subdir}; + if (! -d $t) { + warn "$O: No such directory: $t\n"; + $cv{$svc,$s_subdir} = ''; + $cv{$svc,$s_homedir} = ''; + } + } + } + + # Calculate the actual directory to create (if necessary) + + if ($cv{$svc,$s_homedir} ne '') { + $cv{$svc,$s_actualdir} = $cv{$svc,$s_homedir}; + if ($cv{$svc,$s_subdir} ne '') { + $cv{$svc,$s_actualdir} .= '/' . $cv{$svc,$s_subdir}; + } + if (! $cv{$svc,$s_althomeB}) { + $cv{$svc,$s_actualdir} .= '/' . $username; + } + } + + # Process the "mkdir" and "chgrpdir" configuration variables + + if (($cv{$svc,$s_homedir} ne '') and $cv{$svc,$s_mkdirB}) { + my $t = $cv{$svc,$s_actualdir}; + + if (-d $t) { + print " Directory $t already exists\n" if $verbose; + } elsif (-e $t) { + warn "$O: Not a directory: $t\n"; + $cv{$svc,$s_homedir} = ''; + } else { + print " Directory $t created\n" if $verbose; + mkdir($t, oct($cv{$s_dirmode})) if ! $dryrun; + # Note that this newly-created directory will inherit the + # SGID (set group ID) bit from its parent directory. This + # IS desired, hence, do NOT do a separate chmod()! + if ($cv{$svc,$s_chgrpdirB}) { + chown($uid, $cv{$svc,$s_svcgid}, $t) if ! $dryrun; + } else { + chown($uid, $gid, $t) if ! $dryrun; + } + } + } + + # Process the "mklink" and "linkname" configuration variables + + if (($cv{$svc,$s_homedir} ne '') and $cv{$svc,$s_mklinkB} + and (-d $cv{$svc,$s_actualdir})) { + + # Calculate the actual link name + + $cv{$svc,$s_linkname} =~ s,/$,,; # Remove trailing '/' + + if ($cv{$svc,$s_linkname} eq '') { + $cv{$svc,$s_actuallink} = $homedir . '/' . $svc; + } else { + $cv{$svc,$s_actuallink} = $homedir . '/' . $cv{$svc,$s_linkname}; + } + + # Create the symbolic link, if needed + + my $t = $cv{$svc,$s_actuallink}; + if (-l $t) { + print " Symbolic link $t already exists\n" + if $verbose; + } elsif (-e $t) { + warn "$O: Not a symbolic link: $t\n"; + } else { + print " Symbolic link $t created\n" if $verbose; + symlink($cv{$svc,$s_actualdir}, $t) if ! $dryrun; + if ($cv{$svc,$s_chgrpdirB}) { + lchown($uid, $cv{$svc,$s_svcgid}, $t) if ! $dryrun; + } else { + lchown($uid, $gid, $t) if ! $dryrun; + } + } + } + + # Process the "skelfile" and "chgrpskel" configuration variables + + if (($cv{$svc,$s_homedir} ne '') and ($cv{$svc,$s_skelfile} ne '') + and (-d $cv{$svc,$s_actualdir})) { + + my $t = $cv{$svc,$s_skelfile}; + $cv{$svc,$s_actualsrcf} = $cv{$s_skelother} . '/' . $t; + $cv{$svc,$s_actualdstf} = $cv{$svc,$s_actualdir} . '/' . $t; + + if (-e $cv{$svc,$s_actualdstf}) { + print " File $cv{$svc,$s_actualdstf} already exists\n" + if $verbose; + } elsif (! -r $cv{$svc,$s_actualsrcf}) { + warn "$O: $cv{$svc,$s_actualsrcf}: $!\n"; + } else { + print " File $cv{$svc,$s_actualdstf} created\n" if $verbose; + if ($cv{$svc,$s_chgrpskelB}) { + system(@install, '-m', $cv{$s_filemode}, '-o', $uid, + '-g', $cv{$svc,$s_svcgid}, + $cv{$svc,$s_actualsrcf}, $cv{$svc,$s_actualdstf}) + if ! $dryrun; + } else { + system(@install, '-m', $cv{$s_filemode}, '-o', $uid, '-g', + $gid, $cv{$svc,$s_actualsrcf}, $cv{$svc,$s_actualdstf}) + if ! $dryrun; + } + } + } +} + + +######################################################################### +# End of program + +exit(0); + + +######################################################################### +# Check that the configuration variable contains is a valid boolean value + +sub chkbool($$$$) { + my $svc = $_[0]; # Service name + my $var = $_[1]; # Partial hash key of variable to check + my $new = $_[2]; # Partial hash key of new variable (true bool) + my $def = $_[3]; # Default value, in case of error + + my $val = $cv{$svc,$var}; + + if (grep($_ eq $val, @s_true)) { + $cv{$svc,$new} = 1; + } elsif (grep($_ eq $val, @s_false)) { + $cv{$svc,$new} = 0; + } else { + warn "$O: Illegal value \"$val\" at $conffile:$cl{$var}\n"; + warn "$O: Variable \"$var\[$svc\]\" set to \"$def\"\n"; + + $cv{$svc,$var} = $def; + chkbool($svc, $var, $new, $def); + } +} + + +######################################################################### +# A chown() that works with symbolic links + +sub lchown(@) { + # The chown() function does NOT change the ownership of symbolic links + # under Linux 2.1.81 or later. Hence, make an external call to the + # chown(1) program. This program MUST support the "-h" parameter. + + my $t_uid = shift; + my $t_gid = shift; + + system(@chown, '-h', "$t_uid:$t_gid", @_); +} + + +######################################################################### +# Display usage information + +sub showusage() { + pod2usage(-message => $copyright, -exitval => 0); +} + + +######################################################################### +# Display program version information + +sub showversion() { + print "$copyright\n"; + print <<"DATAEND" +This program is free software that is distributed under the GNU General +Public License, version 2 or later. See /usr/share/common-licenses/GPL +for more information. +DATAEND + ; + exit(0); +} + + +######################################################################### +# Show an error message relating to the command-line and terminate + +sub showcmdlerr(@) { + map { warn "$_\n" } @_; + die "Try `$O --help' for more information.\n"; +} + + +__END__ + + +######################################################################### +# Program documentation in POD format + +=head1 NAME + +adduser.local - adduser(8) local system additions + +=head1 SYNOPSIS + +/usr/local/sbin/adduser.local [B<--dry-run>] [B<--conf> FILE] [B<--quiet>] +[B<--verbose>] [B<--help>] [B<--version>] USERNAME [UID GID HOMEDIR] + +=head1 DESCRIPTION + +The B<adduser.local> script, once installed as +F</usr/local/sbin/adduser.local>, is automatically called by the +adduser(8) system program on a Debian system. This script completes the +creation of a user account by parsing a system-dependent configuration +file, F</etc/adduser.local.conf>. That configuration file lists a number +of "services" to be configured, where each service is simply a convenient +name for directories that must be created, Unix groups to which the user +must be added, files that need to be copied, symbolic links to be created +and so on. + +This script is automatically called by adduser(8) with arguments +I<USERNAME UID GID HOMEDIR>. In addition, this script may be called +manually. In this case, only I<USERNAME> needs to be passed, along with +options as described later in B<OPTIONS>. + +Note that adduser(8) can now perform I<some> of the tasks that +B<adduser.local> does, particularly by using the EXTRA_GROUPS and +ADD_EXTRA_GROUPS variables in F</etc/adduser.conf>. However, +B<adduser.local> is far more flexible than doing just that... + +=head1 OPTIONS + +=over 4 + +=item B<-n>, B<--dry-run> + +Pretend to fulfil everything required, without actually doing anything. + +=item B<-c>, B<--conf> I<FILE> + +Use configuration file I<FILE> instead of the default +F</etc/adduser.local.conf>. + +=item B<-q>, B<--quiet> + +Don't show extraneous output. + +=item B<-v>, B<--verbose> + +Show output about what was done (default). + +=item B<-h>, B<--help> + +Show a brief command-line summary. + +=item B<-V>, B<--version> + +Show the version of the B<adduser.local> script. + +=back + +=head1 RETURN VALUE + +B<adduser.local> returns a successful (zero) exit status if no severe +errors were detected, otherwise a non-zero exit code is returned. + +=head1 EXAMPLES + +To add the user "john" to your system: + + adduser john + +This automatically calls B<adduser.local> with the appropriate arguments. + +If you would like to rerun the B<adduser.local> script (such as after +modifying its configuration file) for the user "john": + + adduser.local john + +=head1 FILES + +=over 4 + +=item F</etc/adduser.local.conf> + +Configuration for B<adduser.local>. The default configuration is +extensively documented. + +=back + +=head1 FEEDBACK + +Your comments, suggestions, corrections and enhancements are always warmly +welcomed! Please send these to: + + Postal: John Zaitseff, + The ZAP Group, + Unit 6, 116 Woodburn Road, + Berala, NSW, 2141, + Australia + + E-mail: J.Zaitseff@zap.org.au + Web: http://www.zap.org.au/software/utils/adduser.local/ + FTP: ftp://ftp.zap.org.au/pub/utils/adduser.local/adduser.local.tar.gz + +=head1 COPYRIGHT + +Copyright (C) 1999-2013, John Zaitseff. + +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., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +=head1 SEE ALSO + +adduser(8) + +=cut |