Annotation of loncom/lcpasswd, revision 1.18
1.1 harris41 1: #!/usr/bin/perl
1.13 harris41 2: # The Learning Online Network with CAPA
3: #
4: # lcpasswd - LON-CAPA setuid script to synchronously change all
5: # filesystem-related passwords (samba, unix, etc)
1.3 harris41 6: #
1.13 harris41 7: # YEAR=2000
8: # 10/27,10/28,10/29,10/30 Scott Harrison
1.3 harris41 9: #
1.12 harris41 10: # YEAR=2001
1.13 harris41 11: # 10/22,10/23,11/13,11/15 Scott Harrison
1.15 matthew 12: #
13: # YEAR=2002
14: # 02/19 Matthew Hall
1.13 harris41 15: #
1.17 foxr 16: # $Id: lcpasswd,v 1.16 2002/08/30 13:37:59 matthew Exp $
1.13 harris41 17: ###
1.12 harris41 18:
19: ###############################################################################
20: ## ##
21: ## ORGANIZATION OF THIS PERL SCRIPT ##
22: ## ##
23: ## 1. Description of script ##
24: ## 2. Invoking script (standard input only) ##
25: ## 3. Example usage inside another piece of code ##
26: ## 4. Description of functions ##
27: ## 5. Exit codes ##
28: ## ##
29: ###############################################################################
1.1 harris41 30:
31: use strict;
32:
1.12 harris41 33: # ------------------------------------------------------- Description of script
34: #
1.1 harris41 35: # This script is a setuid script that should
1.4 harris41 36: # be run by user 'www'. This script allows
37: # for synchronous entry of passwords into
38: # both the /etc/passwd and the /etc/smbpasswd
39: # files.
1.12 harris41 40: #
1.5 harris41 41: # This script works under the same process control mechanism
42: # as lcuseradd and lcpasswd, to make sure that only one of these
43: # processes is running at any one time on the system.
44:
1.12 harris41 45: # --------------------------------------- Invoking script (standard input only)
46: #
1.1 harris41 47: # Standard input usage
48: # First line is USERNAME
1.16 matthew 49: # Second line is NEW PASSWORD
1.1 harris41 50: # Third line is NEW PASSWORD
1.12 harris41 51: #
1.8 harris41 52: # Valid passwords must consist of the
53: # ascii characters within the inclusive
54: # range of 0x20 (32) to 0x7E (126).
55: # These characters are:
56: # SPACE and
57: # !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO
58: # PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
1.12 harris41 59: #
1.8 harris41 60: # Valid user names must consist of ascii
61: # characters that are alphabetical characters
62: # (A-Z,a-z), numeric (0-9), or the underscore
63: # mark (_). (Essentially, the perl regex \w).
1.12 harris41 64: # User names must begin with an alphabetical character
65: # (A-Z,a-z).
1.8 harris41 66:
1.12 harris41 67: # ---------------------------------------------------- Description of functions
68: # enable_root_capability() : have setuid script run as root
69: # disable_root_capability() : have setuid script run as www
70: # try_to_lock() : make sure that another lcpasswd process isn't running
1.4 harris41 71:
1.12 harris41 72: # ------------------------------------------------------------------ Exit codes
1.4 harris41 73: # These are the exit codes.
74: # ( (0,"ok"),
1.7 harris41 75: # (1,"User ID mismatch. This program must be run as user 'www'"),
1.12 harris41 76: # (2,"Error. This program needs 3 command-line arguments (username, old ".
77: # password, new password)."),
1.6 harris41 78: # (3,"Error. Three lines need to be entered into standard input."),
1.12 harris41 79: # (4,"Error. Too many other simultaneous password change requests being ".
80: # made."),
1.6 harris41 81: # (5,"Error. User $username does not exist."),
82: # (6,"Error. Invalid entry of current password."),
1.10 harris41 83: # (7,"Error. Root was not successfully enabled."),
1.12 harris41 84: # (8,"Error. Cannot set password."),
1.10 harris41 85: # (9,"Error. The user name specified has invalid characters."),
86: # (10,"Error. A password entry had an invalid character.") )
1.4 harris41 87:
1.12 harris41 88: # ------------------------------------------------------------- Initializations
1.1 harris41 89: # Security
1.12 harris41 90: $ENV{'PATH'}='/bin:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
91: # information
1.13 harris41 92: delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # nullify potential taints
1.1 harris41 93:
1.12 harris41 94: # Do not print error messages
95: my $noprint=1;
96:
1.18 ! foxr 97: print "In lcpasswd" unless $noprint;
! 98:
1.12 harris41 99: # ----------------------------- Make sure this process is running from user=www
100: my $wwwid=getpwnam('www');
101: &disable_root_capability;
102: if ($wwwid!=$>) {
103: print("User ID mismatch. This program must be run as user 'www'\n")
104: unless $noprint;
1.4 harris41 105: exit 1;
1.1 harris41 106: }
1.12 harris41 107:
108: # ----------------------------------- Start running script with www permissions
1.2 harris41 109: &disable_root_capability;
1.1 harris41 110:
1.12 harris41 111: # --------------------------- Handle case of another lcpasswd process (locking)
1.6 harris41 112: unless (&try_to_lock('/tmp/lock_lcpasswd')) {
1.12 harris41 113: print "Error. Too many other simultaneous password change requests being ".
114: "made.\n" unless $noprint;
1.5 harris41 115: exit 4;
116: }
117:
1.12 harris41 118: # ------- Error-check input, need 3 values (user name, password 1, password 2).
1.4 harris41 119: my @input;
1.12 harris41 120: @input=<>;
121: if (@input!=3) {
122: print("Error. Three lines need to be entered into standard input.\n")
123: unless $noprint;
1.6 harris41 124: unlink('/tmp/lock_lcpasswd');
1.12 harris41 125: exit 3;
1.1 harris41 126: }
1.14 harris41 127: foreach (@input) {chomp;}
1.1 harris41 128:
1.12 harris41 129: my ($username,$password1,$password2)=@input;
1.8 harris41 130: $username=~/^(\w+)$/;
131: my $safeusername=$1;
1.12 harris41 132: if (($username ne $safeusername) or ($safeusername!~/^[A-Za-z]/)) {
1.8 harris41 133: print "Error. The user name specified has invalid characters.\n";
134: unlink('/tmp/lock_lcpasswd');
135: exit 9;
136: }
1.9 harris41 137: my $pbad=0;
1.15 matthew 138: foreach (split(//,$password1)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
139: foreach (split(//,$password2)) {if ((ord($_)<32)||(ord($_)>126)){$pbad=1;}}
1.9 harris41 140: if ($pbad) {
141: print "Error. A password entry had an invalid character.\n";
142: unlink('/tmp/lock_lcpasswd');
143: exit 10;
144: }
1.1 harris41 145:
1.12 harris41 146: # -- Only add user if the two password arguments match.
147: if ($password1 ne $password2) {
148: print "Error. Password mismatch.\n" unless $noprint;
149: unlink('/tmp/lock_lcpasswd');
150: exit 13;
1.1 harris41 151: }
152:
153: # Verify existence of user
1.12 harris41 154: unless(getpwnam($safeusername)) {
1.4 harris41 155: print "Error. User $username does not exist.\n" unless $noprint;
1.6 harris41 156: unlink('/tmp/lock_lcpasswd');
1.4 harris41 157: exit 5;
1.1 harris41 158: }
1.12 harris41 159: &enable_root_capability;
160: ($>,$<)=(0,0);
1.18 ! foxr 161:
! 162: print "Now $> , $< , -invoking pwchange with $safeusername $password1"
1.17 foxr 163: unless $noprint;
1.12 harris41 164: open OUT,"|pwchange $safeusername";
165: print OUT $password1;
166: print OUT "\n";
167: close OUT;
168: ($>,$<)=(0,500);
169:
1.17 foxr 170: print "pwchange done, back to uid 500" unless $noprint;
171:
1.12 harris41 172: if ($?) {
173: exit 8;
1.1 harris41 174: }
1.12 harris41 175: my $userid=getpwnam($safeusername);
176:
1.13 harris41 177: if (-e '/usr/bin/smbpasswd') {
1.12 harris41 178:
179: ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid
180: # environment
1.1 harris41 181:
1.17 foxr 182: # If the -a swithc is put on the smbpasswd
183: # command line, either a new entry will be created or the old one
184: # will be used.
185: # Therefore the old strategy of looking for and adding a dummy entry is
186: # not needed... Finally, the smbpasswd file is in /etc/samba not
187: # /etc/smbpasswd as older versions of the script implied.
188:
189: print "Running smbpasswd" unless $noprint;
190: open(OUT,"|/usr/bin/smbpasswd -s -a $safeusername>/dev/null") or
1.13 harris41 191: die('cannot run smbpasswd');
1.12 harris41 192: print OUT $password2; print OUT "\n";
193: print OUT $password2; print OUT "\n";
1.2 harris41 194: close OUT;
1.12 harris41 195: $<=$wwwid; # unfool the program
1.17 foxr 196: print "smbpasswd done" unless $noprint;
1.2 harris41 197: }
1.12 harris41 198:
1.1 harris41 199: &disable_root_capability;
1.6 harris41 200: unlink('/tmp/lock_lcpasswd');
1.4 harris41 201: exit 0;
1.1 harris41 202:
1.12 harris41 203: # ---------------------------------------------- have setuid script run as root
1.1 harris41 204: sub enable_root_capability {
1.2 harris41 205: if ($wwwid==$>) {
1.18 ! foxr 206: ($<,$>)=($>,0);
! 207: ($(,$))=($),0);
1.1 harris41 208: }
209: else {
210: # root capability is already enabled
211: }
1.2 harris41 212: return $>;
1.1 harris41 213: }
214:
1.12 harris41 215: # ----------------------------------------------- have setuid script run as www
1.1 harris41 216: sub disable_root_capability {
1.2 harris41 217: if ($wwwid==$<) {
1.1 harris41 218: ($<,$>)=($>,$<);
219: ($(,$))=($),$();
220: }
221: else {
222: # root capability is already disabled
223: }
224: }
225:
1.12 harris41 226: # ----------------------- make sure that another lcpasswd process isn't running
1.1 harris41 227: sub try_to_lock {
228: my ($lockfile)=@_;
229: my $currentpid;
230: my $lastpid;
1.5 harris41 231: # Do not manipulate lock file as root
232: if ($>==0) {
233: return 0;
234: }
235: # Try to generate lock file.
236: # Wait 3 seconds. If same process id is in
237: # lock file, then assume lock file is stale, and
238: # go ahead. If process id's fluctuate, try
239: # for a maximum of 10 times.
1.1 harris41 240: for (0..10) {
241: if (-e $lockfile) {
242: open(LOCK,"<$lockfile");
243: $currentpid=<LOCK>;
244: close LOCK;
245: if ($currentpid==$lastpid) {
246: last;
247: }
248: sleep 3;
249: $lastpid=$currentpid;
250: }
251: else {
252: last;
253: }
254: if ($_==10) {
255: return 0;
256: }
257: }
258: open(LOCK,">$lockfile");
259: print LOCK $$;
260: close LOCK;
261: return 1;
262: }
1.13 harris41 263:
264: =head1 NAME
265:
266: lcpasswd - LON-CAPA setuid script to synchronously change all
267: filesystem-related passwords (samba, unix, etc)
268:
269: =head1 DESCRIPTION
270:
271: LON-CAPA setuid script to synchronously change all
272: filesystem-related passwords (samba, unix, etc)
273:
274: =head1 README
275:
276: LON-CAPA setuid script to synchronously change all
277: filesystem-related passwords (samba, unix, etc)
278:
279: =head1 PREREQUISITES
280:
281: =head1 COREQUISITES
282:
283: =pod OSNAMES
284:
285: linux
286:
287: =pod SCRIPT CATEGORIES
288:
289: LONCAPA/Administrative
290:
291: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>