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