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