home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / doc / adduser / examples / adduser.local < prev    next >
Encoding:
Text File  |  2006-07-10  |  27.6 KB  |  812 lines

  1. #!/usr/bin/perl -w
  2.  
  3. #########################################################################
  4. #                                                                       #
  5. #                  ADDUSER Local System Additions v4.6                  #
  6. #                Copyright (C) 1999-2004, John Zaitseff                 #
  7. #                                                                       #
  8. #########################################################################
  9.  
  10. # Author:   John Zaitseff <J.Zaitseff@zap.org.au>
  11. # Date:     23rd September, 2004
  12. # Version:  4.6
  13.  
  14. # This program, once installed as /usr/local/sbin/adduser.local, is auto-
  15. # matically called by the adduser(8) system program on a Debian system.
  16. # This script completes the creation of a user account in a system-
  17. # dependent way.
  18. #
  19. # This script is automatically called by adduser with arguments "username
  20. # uid gid homedir".  See adduser(8) for more details.  In addition, this
  21. # script may be called manually.  In this case, the following syntax
  22. # applies:
  23. #
  24. #     /usr/local/sbin/adduser.local [options] username [uid gid homedir]
  25. #
  26. # where the following options exist:
  27. #
  28. #     --dry-run      -n   - Pretend to fulfil everything required, without
  29. #                           doing anything.
  30. #     --quiet        -q   - Don't show extraneous information.
  31. #     --verbose      -v   - Show information about what was done (default).
  32. #     --help         -h   - Show a brief command-line summary.
  33. #     --version      -V   - Show the version of the adduser.local script.
  34. #     --conf <file>       - Use configuration file <file> instead of the
  35. #                           default /etc/adduser.local.conf.
  36.  
  37.  
  38. # This program, including associated files, is free software.  You may
  39. # distribute it and/or modify it under the terms of the GNU General Public
  40. # License as published by the Free Software Foundation; either Version 2
  41. # of the license, or (at your option) any later version.
  42. #
  43. # This program is distributed in the hope that it will be useful, but
  44. # WITHOUT ANY WARRANTY; without even the implied warranty of
  45. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  46. # General Public License for more details.
  47. #
  48. # You should have received a copy of the GNU General Public License along
  49. # with this program; if not, write to the Free Software Foundation, Inc.,
  50. # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  51.  
  52.  
  53. #########################################################################
  54. # Configuration parameters and default values
  55.  
  56. use strict;
  57.  
  58.  
  59. (our $O = $0)      =~ s,^.*/,,;    # adduser.local script name (without path)
  60. our $version       = '4.6';    # Script version
  61.  
  62. our @adduser       = ('/usr/sbin/adduser', '--quiet');  # adduser(8)
  63. our @chown         = ('/bin/chown');                    # chown(1)
  64. our @install       = ('/usr/bin/install', '-p');        # install(1)
  65.  
  66. our $procmounts    = '/proc/mounts';            # List of current mounts
  67.  
  68. our $s_false       = 'false';    # False string value, in lower case
  69. our $s_true        = 'true';    # True string value, in lower case
  70.  
  71. # These default values are extensively documented in adduser.local.conf.
  72.  
  73. our $d_conffile    = '/etc/adduser.local.conf'; # Configuration file location
  74. our $d_skelother   = '/etc/skel.other';         # Location of skeleton files
  75. our $d_dirmode     = '2755';                    # Octal mode for directories
  76. our $d_filemode    = '0644';                    # Octal mode for files
  77.  
  78. our $d_user        = '';    # Default service user name
  79. our $d_group       = '';    # Default service group name
  80. our $d_addtogroup  = $s_false;    # Default for addtogroup variable
  81. our $d_homedir     = '';    # Default home directory
  82. our $d_subdir      = '';    # Default subdirectory
  83. our $d_althome     = $s_false;    # Default for use alternate home directory
  84. our $d_mounted     = $s_false;    # Default for checking if mounted
  85. our $d_mkdir       = $s_false;    # Default for creating directory
  86. our $d_chgrpdir    = $s_false;    # Default for chgrpdir variable
  87. our $d_mklink      = $s_false;    # Default for creating symbolic link
  88. our $d_linkname    = '';    # Default for symbolic link name
  89. our $d_skelfile    = '';    # Default for skeleton file
  90. our $d_chgrpskel   = $s_false;    # Default for chgrpskel variable
  91.  
  92. # Various strings appearing in the configuration file.  While they are
  93. # case insensitive in the configuration file, they must appear in lower
  94. # case here.
  95.  
  96. our $s_skelother   = 'skelother';
  97. our $s_dirmode     = 'dirmode';
  98. our $s_filemode    = 'filemode';
  99.  
  100. our $s_service     = 'service';
  101.  
  102. our $s_user        = 'user';
  103. our $s_group       = 'group';
  104. our $s_addtogroup  = 'addtogroup';
  105. our $s_homedir     = 'homedir';
  106. our $s_subdir      = 'subdir';
  107. our $s_althome     = 'althome';
  108. our $s_mounted     = 'mounted';
  109. our $s_mkdir       = 'mkdir';
  110. our $s_chgrpdir    = 'chgrpdir';
  111. our $s_mklink      = 'mklink';
  112. our $s_linkname    = 'linkname';
  113. our $s_skelfile    = 'skelfile';
  114. our $s_chgrpskel   = 'chgrpskel';
  115.  
  116. our @s_false       = ($s_false, 'f', 'no',  'n', '0');
  117. our @s_true        = ($s_true,  't', 'yes', 'y', '1');
  118.  
  119. # Strings internal to this program (as used by the %cv hash)
  120.  
  121. our $s_svcuid      = '.svcuid';      # Storage for UID of service's user name
  122. our $s_svcgid      = '.svcgid';      # GID of service's user name or group name
  123. our $s_actualdir   = '.actualdir';   # Actual dir: homedir + subdir + username
  124. our $s_actuallink  = '.actuallink';  # Actual sym link: user homedir + linkname
  125. our $s_actualsrcf  = '.actualsrcf';  # Actual source file: skelother + skelfile
  126. our $s_actualdstf  = '.actualdstf';  # Actual dest file: actualdir + skelfile
  127.  
  128. our $s_addtogroupB = '.addtogroupB'; # Boolean versions of variables
  129. our $s_althomeB    = '.althomeB';
  130. our $s_mountedB    = '.mountedB';
  131. our $s_mkdirB      = '.mkdirB';
  132. our $s_chgrpdirB   = '.chgrpdirB';
  133. our $s_mklinkB     = '.mklinkB';
  134. our $s_chgrpskelB  = '.chgrpskelB';
  135.  
  136.  
  137. #########################################################################
  138. # Initialise global variables
  139.  
  140. our $conffile      = $d_conffile;   # Default configuration file
  141. our $verbose       = 1;            # Be verbose by default
  142. our $dryrun        = 0;             # NOT a dry run by default
  143.  
  144. our @services      = ();            # No services to install by default
  145.  
  146. # %cv is a hash for all configuration variables read in from the
  147. # configuration file.  Global variables are represented by their strings,
  148. # eg, $cv{"skelother"}.  Service-specific variables are represented by the
  149. # service string value, a comma, then their string, eg, $cv{"www","user"}.
  150. # The %cl hash plays a similar role, but contains the line number of the
  151. # configuration.
  152.  
  153. our (%cv, %cl);
  154.  
  155. $cv{$s_skelother} = $d_skelother;  $cl{$s_skelother} = 0;
  156. $cv{$s_dirmode}   = $d_dirmode;    $cl{$s_dirmode}   = 0;
  157. $cv{$s_filemode}  = $d_filemode;   $cl{$s_filemode}  = 0;
  158.  
  159. # For safety's sake, initialise the PATH environment variable
  160.  
  161. $ENV{PATH} = '/usr/sbin:/usr/bin:/sbin:/bin';
  162.  
  163. # Declare some global variables
  164.  
  165. our $username;            # Username for which adduser.local was called
  166. our $uid;            # User's UID
  167. our $gid;            # User's GID
  168. our $homedir;            # User's home directory
  169.  
  170.  
  171. #########################################################################
  172. # Process command-line arguments
  173.  
  174. while ($_ = $ARGV[0]) {
  175.     last if (! /^-/);
  176.     shift @ARGV;
  177.     last if ($_ eq '--');
  178.  
  179.     # Split combined short-form options into single arguments
  180.     if (/^-(\w{2,})/) {
  181.         my @args = split //, $1;
  182.  
  183.         foreach my $arg (@args) {
  184.             $arg = "-$arg";
  185.         }
  186.         unshift @ARGV, @args;
  187.         next;
  188.     }
  189.  
  190.     # Process command-line options
  191.     if    (($_ eq '--conf')    || ($_ eq '-c')) {       # --conf filename
  192.         &chkparam($_);
  193.         $conffile = shift @ARGV;
  194.     }
  195.  
  196.     elsif (($_ eq '--dry-run') || ($_ eq '-n')) {       # --dry-run
  197.         $dryrun = 1;
  198.     }
  199.  
  200.     elsif (($_ eq '--quiet')   || ($_ eq '-q')) {       # --quiet
  201.         $verbose = 0;
  202.     }
  203.  
  204.     elsif (($_ eq '--verbose') || ($_ eq '-v')) {       # --verbose
  205.         $verbose = 1;
  206.     }
  207.  
  208.     elsif (($_ eq '--help')    || ($_ eq '-h')) {       # --help
  209.         &showusage();
  210.         exit(0);
  211.     }
  212.  
  213.     elsif (($_ eq '--version') || ($_ eq '-V')) {       # --version
  214.         &showversion();
  215.         exit(0);
  216.     }
  217.  
  218.     else {
  219.         &showcmdlerr("Unrecognised option: $_");
  220.     }
  221. }
  222.  
  223.  
  224. #########################################################################
  225. # Process additional command-line parameters: username [uid gid homedir]
  226.  
  227. if ($#ARGV < 0) { &showcmdlerr("Missing username parameter"); }
  228. if ($#ARGV > 3) { &showcmdlerr("Too many command-line parameters"); }
  229.  
  230. # Include some sanity checking.  These checks are not particularly
  231. # rigorous, as root can do anything anyway...  It is meant to stop silly
  232. # mistakes, not to stop thinking.  In any case, this script SHOULD only be
  233. # called from adduser(8)...
  234.  
  235. die "$O: Only root can execute this program\n" if ($> != 0) && (! $dryrun);
  236.  
  237. if ($#ARGV == 0) {
  238.     # Only a single parameter: username
  239.  
  240.     $username = $ARGV[0];
  241.  
  242.     (my $t_name, my $t1, $uid, $gid, my $t2, my $t3, my $t4, $homedir)
  243.         = getpwnam($username);
  244.  
  245.     die "$O: No such user: $username\n" if ! $t_name;
  246.  
  247. } elsif ($#ARGV == 3) {
  248.     # Four parameters: username uid gid homedir
  249.  
  250.     $username = $ARGV[0];
  251.     $uid      = $ARGV[1];
  252.     $gid      = $ARGV[2];
  253.     $homedir  = $ARGV[3];
  254.  
  255.     $homedir =~ s,/$,,;             # Remove trailing '/' if present
  256.     (my $t_name, my $t1, my $t_uid, my $t_gid) = getpwnam($username);
  257.  
  258.     die "$O: No such user: $username\n" if ! $t_name;
  259.     die "$O: No such UID: $uid\n" if ! getpwuid($uid);
  260.     die "$O: No such GID: $gid\n" if ! getgrgid($gid);
  261.     die "$O: UID of user $username not the same as $uid\n" if $t_uid != $uid;
  262.     die "$O: GID of user $username not the same as $gid\n" if $t_gid != $gid;
  263.     die "$O: Directory $homedir does not exist\n" if ! -d $homedir;
  264.  
  265. } else {
  266.     &showcmdlerr("Missing uid, gid and/or homedir parameters");
  267. }
  268.  
  269.  
  270. #########################################################################
  271. # Process the configuration file
  272.  
  273. if (! -r $conffile) {
  274.     warn "$O: Cannot read configuration file $conffile:\n";
  275.     warn "$O: $conffile: $!\n";
  276.  
  277.     exit(0);
  278. }
  279.  
  280. print "Processing configuration file $conffile\n" if $verbose;
  281.  
  282. open(CONFFILE, $conffile) || die "$O: $conffile: $!\n";
  283. while (<CONFFILE>) {
  284.     my ($var, $svc, $val);
  285.  
  286.     chomp;
  287.  
  288.     # Skip comments and blank lines
  289.     next if /^\s*#/ || /^\s*$/;
  290.  
  291.     # Try matching a global variable with or without quotes
  292.     if ((($var, $val) = /^\s*(\w+)\s*=\s*(.*)/) == 2) {
  293.  
  294.         # Remove trailing spaces and surrounding quotes
  295.         # (Technically, doing it this way is somewhat sloppy)
  296.         $val =~ s/^(.*?)\s*$/$1/;
  297.         $val =~ s/^\"(.*)\"/$1/;
  298.         $val =~ s/^\'(.*)\'/$1/;
  299.  
  300.         my $lcvar = lc $var;
  301.         my $lcval = lc $val;
  302.  
  303.         # Process the global variable
  304.         if ($lcvar eq $s_service) {
  305.  
  306.             # Special global configuration variable "service"
  307.             my $svc = $lcval;
  308.  
  309.             if (grep((lc $_) eq $svc, @services)) {
  310.                 warn "$O: Service \"$val\" redefined at $conffile:$.\n";
  311.                 next;
  312.             }
  313.  
  314.             push @services, $val;
  315.  
  316.             # Set up default values
  317.  
  318.             $cv{$svc,$s_user}       = $d_user;
  319.             $cv{$svc,$s_group}      = $d_group;
  320.             $cv{$svc,$s_addtogroup} = $d_addtogroup;
  321.             $cv{$svc,$s_homedir}    = $d_homedir;
  322.             $cv{$svc,$s_subdir}     = $d_subdir;
  323.             $cv{$svc,$s_althome}    = $d_althome;
  324.             $cv{$svc,$s_mounted}    = $d_mounted;
  325.             $cv{$svc,$s_mkdir}      = $d_mkdir;
  326.             $cv{$svc,$s_chgrpdir}   = $d_chgrpdir;
  327.             $cv{$svc,$s_mklink}     = $d_mklink;
  328.             $cv{$svc,$s_linkname}   = $d_linkname;
  329.             $cv{$svc,$s_skelfile}   = $d_skelfile;
  330.             $cv{$svc,$s_chgrpskel}  = $d_chgrpskel;
  331.  
  332.             $cl{$svc,$s_user}       = 0;
  333.             $cl{$svc,$s_group}      = 0;
  334.             $cl{$svc,$s_addtogroup} = 0;
  335.             $cl{$svc,$s_homedir}    = 0;
  336.             $cl{$svc,$s_subdir}     = 0;
  337.             $cl{$svc,$s_althome}    = 0;
  338.             $cl{$svc,$s_mounted}    = 0;
  339.             $cl{$svc,$s_mkdir}      = 0;
  340.             $cl{$svc,$s_chgrpdir}   = 0;
  341.             $cl{$svc,$s_mklink}     = 0;
  342.             $cl{$svc,$s_linkname}   = 0;
  343.             $cl{$svc,$s_skelfile}   = 0;
  344.             $cl{$svc,$s_chgrpskel}  = 0;
  345.         }
  346.         else {
  347.             # Ordinary global variable
  348.  
  349.             if (! defined($cv{$lcvar})) {
  350.                 warn "$O: Unknown global variable \"$var\" at $conffile:$.\n";
  351.                 next;
  352.             }
  353.  
  354.             $cv{$lcvar} = $val;
  355.             $cl{$lcvar} = $.;
  356.         }
  357.     }
  358.  
  359.     # Try matching a service variable with or without quotes
  360.     elsif ((($var, $svc, $val) = /^\s*(\w+)\s*\[\s*(\w+)\s*\]\s*=\s*(.*)/) == 3) {
  361.  
  362.         # Remove trailing spaces and surrounding quotes
  363.         $val =~ s/^(.*?)\s*$/$1/;
  364.         $val =~ s/^\"(.*)\"/$1/;
  365.         $val =~ s/^\'(.*)\'/$1/;
  366.  
  367.         my $lcvar = lc $var;
  368.         my $lcsvc = lc $svc;
  369.  
  370.         if (! grep((lc $_) eq $lcsvc, @services)) {
  371.             warn "$O: Undefined service \"$svc\" at $conffile:$.\n";
  372.             next;
  373.         }
  374.         if (! defined($cv{$lcsvc,$lcvar})) {
  375.             warn "$O: Unknown service variable \"$var\" at $conffile:$.\n";
  376.             next;
  377.         }
  378.  
  379.         $cv{$lcsvc,$lcvar} = $val;
  380.         $cl{$lcsvc,$lcvar} = $.;
  381.     }
  382.  
  383.     # Otherwise, it is an error in the configuration file
  384.     else {
  385.         warn "$O: Could not parse $conffile:$.\n";
  386.         next;
  387.     }
  388. }
  389.  
  390. close(CONFFILE) || die "$O: $conffile: $!\n";
  391.  
  392.  
  393. #########################################################################
  394. # Global variables sanity checking
  395. {
  396.     my $t;
  397.  
  398.     # Check "skelother"
  399.  
  400.     if (! -d $cv{$s_skelother}) {
  401.         warn "$O: Directory $cv{$s_skelother} does not exist\n";
  402.     }
  403.  
  404.     # Check "dirmode"
  405.  
  406.     $t = $cv{$s_dirmode};
  407.     if (($t !~ /^[01234567]{1,4}$/) || (oct($t) == 0)) {
  408.         warn "$O: Illegal value \"$t\" at $conffile:$cl{$s_dirmode}\n";
  409.         warn "$O: Global variable \"$s_dirmode\" set to $d_dirmode\n";
  410.         $cv{$s_dirmode} = $d_dirmode;
  411.     }
  412.  
  413.     # Check "filemode"
  414.  
  415.     $t = $cv{$s_filemode};
  416.     if (($t !~ /^[01234567]{1,4}$/) || (oct($t) == 0)) {
  417.         warn "$O: Illegal value \"$t\" at $conffile:$cl{$s_filemode}\n";
  418.         warn "$O: Global variable \"$s_filemode\" set to $d_filemode\n";
  419.         $cv{$s_filemode} = $d_filemode;
  420.     }
  421. }
  422.  
  423.  
  424. #########################################################################
  425. # Actually perform what is required, with appropriate error checking
  426.  
  427. foreach my $service (@services) {
  428.  
  429.     my $svc = lc $service;
  430.     my ($t_user, $t_group, $t_homedir);
  431.  
  432.     print "Processing service \"$service\"\n" if $verbose;
  433.  
  434.     # Check validity of all boolean variables and convert them to true bools
  435.  
  436.     # Note that the notation $hash{$idx1,$idx2} is exactly the same as the
  437.     # expression $hash{$idx1 . $; . $idx2}.  It is for this reason that
  438.     # $svcc is defined.
  439.  
  440.     my $svcc = $svc . $;;    # $svc concatenated with $; ($SUBSEP)
  441.  
  442.     &chkbool($svcc.$s_addtogroup, $svcc.$s_addtogroupB, $d_addtogroup, "$s_addtogroup\[$service\]");
  443.     &chkbool($svcc.$s_althome,    $svcc.$s_althomeB,    $d_althome,    "$s_althome\[$service\]");
  444.     &chkbool($svcc.$s_mounted,    $svcc.$s_mountedB,    $d_mounted,    "$s_mounted\[$service\]");
  445.     &chkbool($svcc.$s_mkdir,      $svcc.$s_mkdirB,      $d_mkdir,      "$s_mkdir\[$service\]");
  446.     &chkbool($svcc.$s_chgrpdir,   $svcc.$s_chgrpdirB,   $d_chgrpdir,   "$s_chgrpdir\[$service\]");
  447.     &chkbool($svcc.$s_mklink,     $svcc.$s_mklinkB,     $d_mklink,     "$s_mklink\[$service\]");
  448.     &chkbool($svcc.$s_chgrpskel,  $svcc.$s_chgrpskelB,  $d_chgrpskel,  "$s_chgrpskel\[$service\]");
  449.  
  450.     # Process the "user" configuration variable
  451.  
  452.     if ($cv{$svc,$s_user} ne '') {
  453.         # Retrieve information about the specified service's user name
  454.  
  455.         (my $t_user, my $t1, $cv{$svc,$s_svcuid}, $cv{$svc,$s_svcgid},
  456.          my $t2, my $t3, my $t4, my $t_homedir)
  457.             = getpwnam $cv{$svc,$s_user};
  458.  
  459.         if (! $t_user) {
  460.             warn "$O: Illegal user name \"$cv{$svc,$s_user}\" at $conffile:$cl{$svc,$s_user}\n";
  461.         } else {
  462.             $cv{$svc,$s_user} = $t_user;
  463.         }
  464.  
  465.         # Only set home directory information if not specified by user
  466.         if ($cv{$svc,$s_homedir} eq '') {
  467.             if ($cv{$svc,$s_althomeB}) {
  468.                 $cv{$svc,$s_homedir} = $homedir;      # From command line
  469.             } else {
  470.                 $cv{$svc,$s_homedir} = $t_homedir;    # From service's home
  471.             }
  472.         }
  473.  
  474.         # If the group parameter is not specified, get the appropriate info
  475.         # from the user information
  476.         if ($cv{$svc,$s_svcgid} && ($cv{$svc,$s_group} eq '')) {
  477.             ($cv{$svc,$s_group}) = getgrgid $cv{$svc,$s_svcgid};
  478.         }
  479.     }
  480.  
  481.     # Process the "group" configuration variable
  482.  
  483.     if ($cv{$svc,$s_group} ne '') {
  484.         # Retrieve info about the group.  Yes, it may have been done
  485.         # above, but specifying "group" can be done without specifying
  486.         # "user".  In addition, a different group can be specified from
  487.         # that used by "user".
  488.  
  489.         ($t_group, my $t1, $cv{$svc,$s_svcgid}) = getgrnam $cv{$svc,$s_group};
  490.  
  491.         if (! $t_group) {
  492.             warn "$O: Illegal group name \"$cv{$svc,$s_group}\" at $conffile:$cl{$svc,$s_group}\n";
  493.  
  494.             $cv{$svc,$s_addtogroup} = $s_false;   $cv{$svc,$s_addtogroupB} = 0;
  495.             $cv{$svc,$s_chgrpdir}   = $s_false;   $cv{$svc,$s_chgrpdirB}   = 0;
  496.             $cv{$svc,$s_chgrpskel}  = $s_false;   $cv{$svc,$s_chgrpskelB}  = 0;
  497.         }
  498.         else {
  499.             $cv{$svc,$s_group} = $t_group;
  500.         }
  501.     }
  502.  
  503.     # Process the "addtogroup" configuration variable
  504.  
  505.     if ($cv{$svc,$s_addtogroupB} && ($cv{$svc,$s_group} ne '')) {
  506.  
  507.         my $t = $cv{$svc,$s_group};
  508.         (my $t_group, my $t1, my $t_gid, my $t_members) = getgrnam $t;
  509.  
  510.         # Check if the user is already a member of that group
  511.  
  512.         if (($t_gid == $gid) || grep($_ eq $username, split(' ', $t_members))) {
  513.             print "    User \"$username\" already in group \"$t\"\n"
  514.                 if $verbose;
  515.         } else {
  516.             print "    Adding user \"$username\" to group \"$t\"\n"
  517.                 if $verbose;
  518.             system(@adduser, $username, $t) if ! $dryrun;
  519.         }
  520.     }
  521.  
  522.     # Process the "mounted" configuration variable
  523.  
  524.     $cv{$svc,$s_homedir} =~ s,/$,,;             # Remove trailing / on homedir
  525.     $cv{$svc,$s_subdir}  =~ s,^/,,;             # Remove leading / on subdir
  526.     $cv{$svc,$s_subdir}  =~ s,/$,,;             # Remove trailing / on subdir
  527.  
  528.     if (($cv{$svc,$s_homedir} ne '') && $cv{$svc,$s_mountedB}) {
  529.         # Need to check for "mounted" before checking for the existence of
  530.         # of the service's home directory.
  531.  
  532.         if (! -r $procmounts) {
  533.             warn "$O: $procmounts: $!\n";
  534.         } else {
  535.             my ($t_dev, $t_mntpoint, $t_type, $t_options);
  536.             my $ismounted = 0;
  537.             my $t_dir = $cv{$svc,$s_homedir} . '/';
  538.  
  539.             # Open mounts table and process it
  540.  
  541.             open(MOUNTS, $procmounts) || die "$O: $procmounts: $!\n";
  542.             while (<MOUNTS>) {
  543.                 chomp;
  544.                 ($t_dev, $t_mntpoint, $t_type, $t_options) = split;
  545.                 if ($t_mntpoint !~ m,/$,) { $t_mntpoint .= '/'; }
  546.  
  547.                 # Check if the service's home directory is mounted
  548.                 # Skip "/" as that is always mounted
  549.                 if (($t_mntpoint ne '/') &&
  550.                     (substr($t_dir, 0, length($t_mntpoint))
  551.                         eq $t_mntpoint)) {
  552.                     $ismounted = 1;
  553.                 }
  554.             }
  555.             close(MOUNTS) || die "$O: $procmounts: $!\n";
  556.  
  557.             if (! $ismounted) {
  558.                 print "    Directory $cv{$svc,$s_homedir} not mounted\n"
  559.                     if $verbose;
  560.                 $cv{$svc,$s_homedir} = '';
  561.             }
  562.         }
  563.     }
  564.  
  565.     # Process the "homedir" and "subdir" configuration variables
  566.  
  567.     if ($cv{$svc,$s_homedir} ne '') {
  568.         if (! -d $cv{$svc,$s_homedir}) {
  569.             warn "$O: Directory $cv{$svc,$s_homedir} does not exist\n";
  570.             $cv{$svc,$s_homedir} = '';
  571.         }
  572.         elsif (($cv{$svc,$s_subdir} ne '') && (! $cv{$svc,$s_althomeB})) {
  573.             my $t = $cv{$svc,$s_homedir} . '/' . $cv{$svc,$s_subdir};
  574.             if (! -d $t) {
  575.                 warn "$O: Directory $t does not exist\n";
  576.                 $cv{$svc,$s_subdir} = '';
  577.                 $cv{$svc,$s_homedir} = '';
  578.             }
  579.         }
  580.     }
  581.  
  582.     # Calculate the actual directory to create (if necessary)
  583.  
  584.     if ($cv{$svc,$s_homedir} ne '') {
  585.         $cv{$svc,$s_actualdir} = $cv{$svc,$s_homedir};
  586.         if ($cv{$svc,$s_subdir} ne '') {
  587.             $cv{$svc,$s_actualdir} .= '/' . $cv{$svc,$s_subdir};
  588.         }
  589.         if (! $cv{$svc,$s_althomeB}) {
  590.             $cv{$svc,$s_actualdir} .= '/' . $username;
  591.         }
  592.     }
  593.  
  594.     # Process the "mkdir" and "chgrpdir" configuration variables
  595.  
  596.     if (($cv{$svc,$s_homedir} ne '') && $cv{$svc,$s_mkdirB}) {
  597.         my $t = $cv{$svc,$s_actualdir};
  598.  
  599.         if (-d $t) {
  600.             print "    Directory $t already exists\n" if $verbose;
  601.         } elsif (-e $t) {
  602.             warn "$O: $t is not a directory\n";
  603.             $cv{$svc,$s_homedir} = '';
  604.         } else {
  605.             print "    Directory $t created\n" if $verbose;
  606.             mkdir($t, oct($cv{$s_dirmode})) if ! $dryrun;
  607.                 # Note that this newly-created directory will inherit the
  608.                 # SGID (set group ID) bit from its parent directory.  This
  609.                 # IS desired, hence, do NOT do a separate chmod()!
  610.             if ($cv{$svc,$s_chgrpdirB}) {
  611.                 chown($uid, $cv{$svc,$s_svcgid}, $t) if ! $dryrun;
  612.             } else {
  613.                 chown($uid, $gid, $t) if ! $dryrun;
  614.             }
  615.         }
  616.     }
  617.  
  618.     # Process the "mklink" and "linkname" configuration variables
  619.  
  620.     if (($cv{$svc,$s_homedir} ne '') && $cv{$svc,$s_mklinkB}
  621.         && (-d $cv{$svc,$s_actualdir})) {
  622.  
  623.         # Calculate the actual link name
  624.  
  625.         $cv{$svc,$s_linkname} =~ s,/$,,;        # Remove trailing '/'
  626.  
  627.         if ($cv{$svc,$s_linkname} eq '') {
  628.             $cv{$svc,$s_actuallink} = $homedir . '/' . $service;
  629.         } else {
  630.             $cv{$svc,$s_actuallink} = $homedir . '/' . $cv{$svc,$s_linkname};
  631.         }
  632.  
  633.         # Create the symbolic link, if needed
  634.  
  635.         my $t = $cv{$svc,$s_actuallink};
  636.         if (-l $t) {
  637.             print "    Symbolic link $t already exists\n"
  638.                 if $verbose;
  639.         } elsif (-e $t) {
  640.             warn "$O: $t is not a symbolic link\n";
  641.         } else {
  642.             print "    Symbolic link $t created\n" if $verbose;
  643.             symlink($cv{$svc,$s_actualdir}, $t) if ! $dryrun;
  644.             if ($cv{$svc,$s_chgrpdirB}) {
  645.                 &lchown($uid, $cv{$svc,$s_svcgid}, $t) if ! $dryrun;
  646.             } else {
  647.                 &lchown($uid, $gid, $t) if ! $dryrun;
  648.             }
  649.                 # Note that chown can NOT be used on Linux versions 2.1.81
  650.                 # or later, as it changes the ownership of the TARGET of
  651.                 # the symbolic link.
  652.         }
  653.     }
  654.  
  655.     # Process the "skelfile" and "chgrpskel" configuration variables
  656.  
  657.     if (($cv{$svc,$s_homedir} ne '') && ($cv{$svc,$s_skelfile} ne '')
  658.         && (-d $cv{$svc,$s_actualdir})) {
  659.  
  660.         my $t = $cv{$svc,$s_skelfile};
  661.         $cv{$svc,$s_actualsrcf} = $cv{$s_skelother} . '/' . $t;
  662.         $cv{$svc,$s_actualdstf} = $cv{$svc,$s_actualdir} . '/' . $t;
  663.  
  664.         if (-e $cv{$svc,$s_actualdstf}) {
  665.             print "    File $cv{$svc,$s_actualdstf} already exists\n"
  666.                 if $verbose;
  667.         } elsif (! -r $cv{$svc,$s_actualsrcf}) {
  668.             warn "$O: $cv{$svc,$s_actualsrcf}: $!\n";
  669.         } else {
  670.             print "    File $cv{$svc,$s_actualdstf} created\n" if $verbose;
  671.             if ($cv{$svc,$s_chgrpskelB}) {
  672.                 system(@install, '-m', $cv{$s_filemode}, '-o', $uid,
  673.                        '-g', $cv{$svc,$s_svcgid},
  674.                        $cv{$svc,$s_actualsrcf}, $cv{$svc,$s_actualdstf})
  675.                     if ! $dryrun;
  676.             } else {
  677.                 system(@install, '-m', $cv{$s_filemode}, '-o', $uid, '-g',
  678.                        $gid, $cv{$svc,$s_actualsrcf}, $cv{$svc,$s_actualdstf})
  679.                     if ! $dryrun;
  680.             }
  681.         }
  682.     }
  683. }
  684.  
  685.  
  686. #########################################################################
  687. # End of program
  688.  
  689. exit(0);
  690.  
  691.  
  692. #########################################################################
  693. # Show an error message relating to the command-line and terminate
  694.  
  695. sub showcmdlerr {
  696.     if (@_) {
  697.         foreach my $line (@_) {
  698.             warn "$O: $line\n";
  699.         }
  700.     }
  701.  
  702.     die "\nUsage:\n" .
  703.         "    $0 [--dry-run] [--conf filename]\n" .
  704.         "        [--quiet] [--verbose] [--help] [--version] [-nqvhV]\n" .
  705.         "        username [uid gid homedir]\n";
  706. }
  707.  
  708.  
  709. #########################################################################
  710. # Check that the next argument is a valid parameter
  711.  
  712. sub chkparam ($) {
  713.     my $arg = $_[0];
  714.     if (! $ARGV[0] || ($ARGV[0] =~ /^-/)) {
  715.         &showcmdlerr("Missing argument for $arg");
  716.     }
  717. }
  718.  
  719.  
  720. #########################################################################
  721. # Check that the configuration variable contains is a valid boolean value
  722.  
  723. sub chkbool ($$$$) {
  724.     my $var  = $_[0];           # Hash key of variable to check
  725.     my $new  = $_[1];           # Hash key of new variable, a true boolean
  726.     my $def  = $_[2];           # Default value, in case of error
  727.     my $pvar = $_[3];           # Config. variable name (for warnings)
  728.  
  729.     my $val = lc $cv{$var};
  730.  
  731.     if (grep($_ eq $val, @s_true)) {
  732.         $cv{$new} = 1;
  733.     } elsif (grep($_ eq $val, @s_false)) {
  734.         $cv{$new} = 0;
  735.     } else {
  736.         warn "$O: Illegal value \"$cv{$var}\" at $conffile:$cl{$var}\n";
  737.         warn "$O: Variable \"$pvar\" set to $def\n";
  738.  
  739.         $cv{$var} = $def;
  740.         &chkbool($var, $new, $def, $pvar);
  741.     }
  742. }
  743.  
  744.  
  745. #########################################################################
  746. # A chown() that works with symbolic links
  747.  
  748. sub lchown {
  749.     # The chown() function does NOT change the ownership of symbolic links
  750.     # under Linux 2.1.81 or later.  Hence, make an external call to the
  751.     # chown(1) program.  This program MUST support the "-h" parameter.
  752.  
  753.     my $t_uid = shift;
  754.     my $t_gid = shift;
  755.  
  756.     system(@chown, '-h', "$t_uid:$t_gid", @_);
  757. }
  758.  
  759.  
  760. #########################################################################
  761. # Display usage information
  762.  
  763. sub showusage () {
  764.     print <<"DATAEND"
  765.  
  766. $O v$version --- adduser(8) local system additions.
  767. Copyright (C) 1999-2004, John Zaitseff.
  768.  
  769. This program, once installed as /usr/local/sbin/adduser.local, is auto-
  770. matically called by the adduser(8) system program on a Debian system.
  771. This script completes the creation of a user account in a system-
  772. dependent way.
  773.  
  774. This script is automatically called by adduser with arguments \"username
  775. uid gid homedir\".  See adduser(8) for more details.  In addition, this
  776. script may be called manually.  In this case, the following syntax
  777. applies:
  778.  
  779.     /usr/local/sbin/adduser.local [options] username [uid gid homedir]
  780.  
  781. where the following options exist:
  782.  
  783.     --dry-run      -n   - Pretend to fulfil everything required, without
  784.                           doing anything.
  785.     --quiet        -q   - Don\'t show extraneous information.
  786.     --verbose      -v   - Show information about what was done (default).
  787.     --help         -h   - Show a brief command-line summary.
  788.     --version      -V   - Show the version of the adduser.local script.
  789.     --conf <file>       - Use configuration file <file> instead of the
  790.                           default $d_conffile.
  791.  
  792. DATAEND
  793.  
  794. }
  795.  
  796.  
  797. #########################################################################
  798. # Display program version information
  799.  
  800. sub showversion () {
  801.     print <<"DATAEND"
  802.  
  803. $O v$version --- adduser(8) local system additions.
  804. Copyright (C) 1999-2004, John Zaitseff.
  805.  
  806. This program, including associated files, is distributed under the GNU General
  807. Public License.  See /usr/share/common-licenses/GPL for more information.
  808.  
  809. DATAEND
  810.  
  811. }
  812.