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