Annotation of loncom/lcuseradd, revision 1.16
1.1 harris41 1: #!/usr/bin/perl
1.16 ! harris41 2:
! 3: # The Learning Online Network with CAPA
1.1 harris41 4: #
1.16 ! harris41 5: # lcuseradd - LON-CAPA setuid script to coordinate all actions
! 6: # with adding a user with filesystem privileges (e.g. author)
1.1 harris41 7: #
1.16 ! harris41 8: # YEAR=2000
! 9: # 10/27,10/29,10/30 Scott Harrison
1.15 harris41 10: # YEAR=2001
1.16 ! harris41 11: # 10/21,11/13,11/15 Scott Harrison
! 12: #
! 13: # $Id: lcuseradd,v 1.15 2001/10/23 03:42:30 harris41 Exp $
! 14: ###
1.15 harris41 15:
16: ###############################################################################
17: ## ##
18: ## ORGANIZATION OF THIS PERL SCRIPT ##
19: ## ##
20: ## 1. Description of script ##
21: ## 2. Invoking script (standard input) ##
22: ## 3. Example usage inside another piece of code ##
23: ## 4. Description of functions ##
24: ## 5. Exit codes ##
25: ## 6. Initializations ##
26: ## 7. Make sure this process is running from user=www ##
27: ## 8. Start running script with www permissions ##
28: ## 9. Handle case of another lcpasswd process (locking) ##
29: ## 10. Error-check input, need 3 values (user name, password 1, password 2) ##
30: ## 11. Start running script with root permissions ##
31: ## 12. Add user and make www a member of the user-specific group ##
32: ## 13. Set password ##
33: ## 14. Make final modifications to the user directory ##
34: ## 15. Exit script (unlock) ##
35: ## ##
36: ###############################################################################
1.1 harris41 37:
38: use strict;
39:
1.15 harris41 40: # ------------------------------------------------------- Description of script
41: #
1.1 harris41 42: # This script is a setuid script that should
43: # be run by user 'www'. It creates a /home/USERNAME directory
44: # as well as a /home/USERNAME/public_html directory.
1.15 harris41 45: # It adds a user to the unix system.
1.2 harris41 46: # Passwords are set with lcpasswd.
47: # www becomes a member of this user group.
1.1 harris41 48:
1.15 harris41 49: # -------------- Invoking script (standard input versus command-line arguments)
50: #
51: # Standard input (STDIN) usage
1.1 harris41 52: # First line is USERNAME
53: # Second line is PASSWORD
1.3 harris41 54: # Third line is PASSWORD
1.15 harris41 55: #
56: # Command-line arguments [USERNAME] [PASSWORD] [PASSWORD]
57: # Yes, but be very careful here (don't pass shell commands)
58: # and this is only supported to allow perl-system calls.
59: #
1.7 harris41 60: # Valid passwords must consist of the
61: # ascii characters within the inclusive
62: # range of 0x20 (32) to 0x7E (126).
63: # These characters are:
64: # SPACE and
65: # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
66: # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
1.15 harris41 67: #
1.7 harris41 68: # Valid user names must consist of ascii
69: # characters that are alphabetical characters
70: # (A-Z,a-z), numeric (0-9), or the underscore
71: # mark (_). (Essentially, the perl regex \w).
1.15 harris41 72: # User names must begin with an alphabetical character
73: # (A-Z,a-z).
1.7 harris41 74:
1.15 harris41 75: # ---------------------------------- Example usage inside another piece of code
1.4 harris41 76: # Usage within code
77: #
1.15 harris41 78: # $exitcode=
79: # system("/home/httpd/perl/lcuseradd","NAME","PASSWORD1","PASSWORD2")/256;
1.4 harris41 80: # print "uh-oh" if $exitcode;
81:
1.15 harris41 82: # ---------------------------------------------------- Description of functions
83: # enable_root_capability() : have setuid script run as root
84: # disable_root_capability() : have setuid script run as www
85: # try_to_lock() : make sure that another lcpasswd process isn't running
86:
87: # ------------------------------------------------------------------ Exit codes
1.4 harris41 88: # These are the exit codes.
1.13 harris41 89: # ( (0,"ok"),
90: # (1,"User ID mismatch. This program must be run as user 'www'"),
1.15 harris41 91: # (2,"Error. This program needs 3 command-line arguments (username, ".
92: # "password 1, password 2)."),
1.13 harris41 93: # (3,"Error. Three lines should be entered into standard input."),
1.15 harris41 94: # (4,"Error. Too many other simultaneous password change requests being ".
95: # "made."),
1.13 harris41 96: # (5,"Error. User $username does not exist."),
97: # (6,"Error. Could not make www a member of the group \"$safeusername\"."),
98: # (7,"Error. Root was not successfully enabled.),
1.15 harris41 99: # (8,"Error. Cannot set password."),
1.13 harris41 100: # (9,"Error. The user name specified has invalid characters."),
101: # (10,"Error. A password entry had an invalid character."),
102: # (11,"Error. User already exists.),
1.15 harris41 103: # (12,"Error. Something went wrong with the addition of user ".
104: # "\"$safeusername\"."),
1.13 harris41 105: # (13,"Error. Password mismatch."),
1.4 harris41 106:
1.15 harris41 107: # ------------------------------------------------------------- Initializations
1.1 harris41 108: # Security
1.15 harris41 109: $ENV{'PATH'}='/bin/:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
110: # information
1.16 ! harris41 111: delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # nullify potential taints
1.2 harris41 112:
1.15 harris41 113: # Do not print error messages.
114: my $noprint=1;
115:
116: # ----------------------------- Make sure this process is running from user=www
117: my $wwwid=getpwnam('www');
118: &disable_root_capability;
119: if ($wwwid!=$>) {
120: print("User ID mismatch. This program must be run as user 'www'\n")
121: unless $noprint;
1.4 harris41 122: exit 1;
123: }
1.15 harris41 124:
125: # ----------------------------------- Start running script with www permissions
1.4 harris41 126: &disable_root_capability;
127:
1.15 harris41 128: # --------------------------- Handle case of another lcpasswd process (locking)
1.4 harris41 129: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
1.15 harris41 130: print "Error. Too many other simultaneous password change requests being ".
131: "made.\n" unless $noprint;
1.4 harris41 132: exit 4;
133: }
134:
1.15 harris41 135: # ------- Error-check input, need 3 values (user name, password 1, password 2).
1.4 harris41 136: my @input;
1.5 harris41 137: if (@ARGV==3) {
1.4 harris41 138: @input=@ARGV;
139: }
140: elsif (@ARGV) {
1.15 harris41 141: print("Error. This program needs 3 command-line arguments (username, ".
142: "password 1, password 2).\n") unless $noprint;
1.4 harris41 143: unlink('/tmp/lock_lcpasswd');
144: exit 2;
145: }
146: else {
147: @input=<>;
1.5 harris41 148: if (@input!=3) {
1.15 harris41 149: print("Error. Three lines should be entered into standard input.\n")
150: unless $noprint;
1.4 harris41 151: unlink('/tmp/lock_lcpasswd');
152: exit 3;
153: }
1.15 harris41 154: map {chomp} @input;
1.4 harris41 155: }
156:
157: my ($username,$password1,$password2)=@input;
158: $username=~/^(\w+)$/;
159: my $safeusername=$1;
1.15 harris41 160: if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
161: print "Error. The user name specified has invalid characters.\n"
162: unless $noprint;
1.8 harris41 163: unlink('/tmp/lock_lcpasswd');
164: exit 9;
165: }
166: my $pbad=0;
1.9 harris41 167: map {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}} (split(//,$password1));
168: map {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}} (split(//,$password2));
1.8 harris41 169: if ($pbad) {
170: print "Error. A password entry had an invalid character.\n";
171: unlink('/tmp/lock_lcpasswd');
172: exit 10;
173: }
1.5 harris41 174:
1.15 harris41 175: # -- Only add user if we can create a brand new home directory (/home/username)
1.7 harris41 176: if (-e "/home/$safeusername") {
177: print "Error. User already exists.\n" unless $noprint;
178: unlink('/tmp/lock_lcpasswd');
1.13 harris41 179: exit 11;
1.7 harris41 180: }
181:
1.15 harris41 182: # -- Only add user if the two password arguments match.
1.5 harris41 183: if ($password1 ne $password2) {
1.6 harris41 184: print "Error. Password mismatch.\n" unless $noprint;
1.5 harris41 185: unlink('/tmp/lock_lcpasswd');
1.13 harris41 186: exit 13;
1.5 harris41 187: }
1.4 harris41 188:
1.15 harris41 189: # ---------------------------------- Start running script with root permissions
1.4 harris41 190: &enable_root_capability;
191:
1.15 harris41 192: # ------------------- Add user and make www a member of the user-specific group
193: # -- Add user
1.5 harris41 194: if (system('/usr/sbin/useradd','-c','LON-CAPA user',$safeusername)) {
1.15 harris41 195: print "Error. Something went wrong with the addition of user ".
196: "\"$safeusername\".\n" unless $noprint;
1.4 harris41 197: unlink('/tmp/lock_lcpasswd');
1.13 harris41 198: exit 12;
1.4 harris41 199: }
1.7 harris41 200:
201: # Make www a member of that user group.
1.5 harris41 202: if (system('/usr/sbin/usermod','-G',$safeusername,'www')) {
1.15 harris41 203: print "Error. Could not make www a member of the group ".
204: "\"$safeusername\".\n" unless $noprint;
1.5 harris41 205: unlink('/tmp/lock_lcpasswd');
206: exit 6;
207: }
208:
1.15 harris41 209: # ---------------------------------------------------------------- Set password
210: # Set password with lcpasswd (which creates smbpasswd entry).
1.2 harris41 211:
1.15 harris41 212: unlink('/tmp/lock_lcpasswd');
213: &disable_root_capability;
1.16 ! harris41 214: ($>,$<)=($wwwid,$wwwid);
! 215: open OUT,"|/home/httpd/perl/lcpasswd";
1.15 harris41 216: print OUT $safeusername;
217: print OUT "\n";
218: print OUT $password1;
219: print OUT "\n";
220: print OUT $password1;
221: print OUT "\n";
222: close OUT;
1.16 ! harris41 223: ($>,$<)=($wwwid,0);
1.15 harris41 224: if ($?) {
225: exit 8;
1.8 harris41 226: }
1.15 harris41 227: &enable_root_capability;
1.8 harris41 228:
1.15 harris41 229: # ------------------------------ Make final modifications to the user directory
230: # -- Add a public_html file with a stand-in index.html file
1.8 harris41 231:
1.15 harris41 232: # system('/bin/chmod','-R','0660',"/home/$safeusername");
233: system('/bin/chmod','0710',"/home/$safeusername");
234: mkdir "/home/$safeusername/public_html",2760;
1.11 harris41 235: open OUT,">/home/$safeusername/public_html/index.html";
1.8 harris41 236: print OUT<<END;
1.15 harris41 237: <html>
238: <head>
239: <title>$safeusername</title>
240: </head>
241: <body>
242: <h1>$safeusername</h1>
243: <p>
1.8 harris41 244: Learning Online Network
1.15 harris41 245: </p>
246: <p>
1.8 harris41 247: This area provides for:
1.15 harris41 248: </p>
249: <ul>
250: <li>resource construction</li>
251: <li>resource publication</li>
252: <li>record-keeping</li>
1.8 harris41 253: </UL>
254: </BODY>
255: </HTML>
256: END
257: close OUT;
1.11 harris41 258: system('/bin/chown','-R',"$safeusername:$safeusername","/home/$safeusername");
1.15 harris41 259:
260: # -------------------------------------------------------- Exit script
1.8 harris41 261: &disable_root_capability;
262: exit 0;
1.1 harris41 263:
1.15 harris41 264: # ---------------------------------------------- Have setuid script run as root
1.5 harris41 265: sub enable_root_capability {
266: if ($wwwid==$>) {
267: ($<,$>)=($>,$<);
268: ($(,$))=($),$();
269: }
270: else {
271: # root capability is already enabled
272: }
273: return $>;
274: }
275:
1.15 harris41 276: # ----------------------------------------------- Have setuid script run as www
1.5 harris41 277: sub disable_root_capability {
278: if ($wwwid==$<) {
279: ($<,$>)=($>,$<);
280: ($(,$))=($),$();
281: }
282: else {
283: # root capability is already disabled
284: }
285: }
286:
1.15 harris41 287: # ----------------------- Make sure that another lcpasswd process isn't running
1.5 harris41 288: sub try_to_lock {
289: my ($lockfile)=@_;
290: my $currentpid;
291: my $lastpid;
292: # Do not manipulate lock file as root
293: if ($>==0) {
294: return 0;
295: }
296: # Try to generate lock file.
297: # Wait 3 seconds. If same process id is in
298: # lock file, then assume lock file is stale, and
299: # go ahead. If process id's fluctuate, try
300: # for a maximum of 10 times.
301: for (0..10) {
302: if (-e $lockfile) {
303: open(LOCK,"<$lockfile");
304: $currentpid=<LOCK>;
305: close LOCK;
306: if ($currentpid==$lastpid) {
307: last;
308: }
309: sleep 3;
310: $lastpid=$currentpid;
311: }
312: else {
313: last;
314: }
315: if ($_==10) {
316: return 0;
317: }
318: }
319: open(LOCK,">$lockfile");
320: print LOCK $$;
321: close LOCK;
322: return 1;
323: }
1.16 ! harris41 324:
! 325: =head1 NAME
! 326:
! 327: lcuseradd - LON-CAPA setuid script to coordinate all actions
! 328: with adding a user with filesystem privileges (e.g. author)
! 329:
! 330: =head1 DESCRIPTION
! 331:
! 332: lcuseradd - LON-CAPA setuid script to coordinate all actions
! 333: with adding a user with filesystem privileges (e.g. author)
! 334:
! 335: =head1 README
! 336:
! 337: lcuseradd - LON-CAPA setuid script to coordinate all actions
! 338: with adding a user with filesystem privileges (e.g. author)
! 339:
! 340: =head1 PREREQUISITES
! 341:
! 342: =head1 COREQUISITES
! 343:
! 344: =pod OSNAMES
! 345:
! 346: linux
! 347:
! 348: =pod SCRIPT CATEGORIES
! 349:
! 350: LONCAPA/Administrative
! 351:
! 352: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>