File:
[LON-CAPA] /
loncom /
lcpasswd
Revision
1.6:
download - view:
text,
annotated -
select for diffs
Sat Oct 28 19:22:19 2000 UTC (23 years, 11 months ago) by
harris41
Branches:
MAIN
CVS tags:
HEAD
lcpasswd should be in a workable mode now. I replaced some "'s with ' characters
to make code more efficient (avoid interpolation). the outline of lcuserdel is in place
now. -Scott
1: #!/usr/bin/perl
2: #
3: # lcpasswd
4: #
5: # Scott Harrison
6: # SH: October 27, 2000
7: # SH: October 28, 2000
8:
9: use strict;
10:
11: # This script is a setuid script that should
12: # be run by user 'www'. This script allows
13: # for synchronous entry of passwords into
14: # both the /etc/passwd and the /etc/smbpasswd
15: # files.
16:
17: # This script works under the same process control mechanism
18: # as lcuseradd and lcpasswd, to make sure that only one of these
19: # processes is running at any one time on the system.
20:
21: # Standard input usage
22: # First line is USERNAME
23: # Second line is CURRENT PASSWORD
24: # Third line is NEW PASSWORD
25:
26: # Command-line arguments
27: # Yes, but be very careful here (don't pass shell commands)
28: # and this is only supported to allow perl-system calls.
29:
30: # Usage within code
31: # Note: NEVER run as system("/home/httpd/perl/lcpasswd NAME OLDPWD NEWPWD")
32: #
33: # $exitcode=system("/home/httpd/perl/lcpasswd","NAME","OLDPWD","NEWPWD")/256;
34: # print "uh-oh" if $exitcode;
35:
36: # These are the exit codes.
37: # ( (0,"ok"),
38: # (1,"User ID mismatch. This program must be run as user 'www'),
39: # (2,"Error. This program does not accept command-line arguments."),
40: # (3,"Error. Three lines need to be entered into standard input."),
41: # (4,"Error. Too many other simultaneous password change requests being made."),
42: # (5,"Error. User $username does not exist."),
43: # (6,"Error. Invalid entry of current password."),
44: # (7,"Error. Root was not successfully enabled.") )
45: # (8,"Error. Cannot open /etc/passwd.") )
46:
47: # Security
48: $ENV{'PATH'}='/bin:/usr/bin'; # Nullify path information except for what smbpasswd needs
49: $ENV{'BASH_ENV'}=''; # Nullify shell environment information.
50:
51: # Do not print error messages if there are command-line arguments
52: my $noprint=0;
53: if (@ARGV) {
54: $noprint=1;
55: }
56:
57: # Read in /etc/passwd, and make sure this process is running from user=www
58: open (IN, '</etc/passwd');
59: my @lines=<IN>;
60: close IN;
61: my $wwwid;
62: for my $l (@lines) {
63: chop $l;
64: my @F=split(/\:/,$l);
65: if ($F[0] eq 'www') {$wwwid=$F[2];}
66: }
67: if ($wwwid!=$<) {
68: print("User ID mismatch. This program must be run as user 'www'\n") unless $noprint;
69: exit 1;
70: }
71: &disable_root_capability;
72:
73: # Handle case of another lcpasswd process
74: unless (&try_to_lock('/tmp/lock_lcpasswd')) {
75: print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;
76: exit 4;
77: }
78:
79: # Gather input. Should only be 3 values.
80: my @input;
81: if (@ARGV==3) {
82: @input=@ARGV;
83: }
84: elsif (@ARGV) {
85: print("Error. This program needs 3 command-line arguments (username, old password, new password).\n") unless $noprint;
86: unlink('/tmp/lock_lcpasswd');
87: exit 2;
88: }
89: else {
90: @input=<>;
91: if (@input!=3) {
92: print("Error. Three lines need to be entered into standard input.\n") unless $noprint;
93: unlink('/tmp/lock_lcpasswd');
94: exit 3;
95: }
96: map {chop} @input;
97: }
98:
99: my ($username,$oldpwd,$newpwd)=@input;
100:
101: # Grab the line corresponding to username
102: my ($userid,$useroldcryptpwd);
103: my @F; my @U;
104: for my $l (@lines) {
105: @F=split(/\:/,$l);
106: if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}
107: }
108:
109: # Verify existence of user
110: if (!defined($userid)) {
111: print "Error. User $username does not exist.\n" unless $noprint;
112: unlink('/tmp/lock_lcpasswd');
113: exit 5;
114: }
115:
116: # Verify password entry
117: if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {
118: print "Error. Invalid entry of current password.\n" unless $noprint;
119: unlink('/tmp/lock_lcpasswd');
120: exit 6;
121: }
122:
123: # Construct new password entry (random salt)
124: my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
125: $U[1]=$newcryptpwd;
126: my $userline=join(':',@U);
127: my $rootid=&enable_root_capability;
128: if ($rootid!=0) {
129: print "Error. Root was not successfully enabled.\n" unless $noprint;
130: unlink('/tmp/lock_lcpasswd');
131: exit 7;
132: }
133: open PASSWORDFILE, '>/etc/passwd' or (print("Error. Cannot open /etc/passwd.\n") && unlink('/tmp/lock_lcpasswd') && exit(8));
134: for my $l (@lines) {
135: @F=split(/\:/,$l);
136: if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}
137: else {print PASSWORDFILE "$l\n";}
138: }
139: close PASSWORDFILE;
140: $username=~/^(\w+)$/;
141: my $safeusername=$1;
142: ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid environment
143: unless (-e '/etc/smbpasswd') {
144: open (OUT,'>/etc/smbpasswd'); close OUT;
145: }
146: my $smbexist=0;
147: open (IN, '</etc/smbpasswd');
148: my @lines=<IN>;
149: close IN;
150: for my $l (@lines) {
151: chop $l;
152: my @F=split(/\:/,$l);
153: if ($F[0] eq $username) {$smbexist=1;}
154: }
155: unless ($smbexist) {
156: open(OUT,'>>/etc/smbpasswd');
157: print OUT join(':',($safeusername,$userid,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,'/bin/bash')) . "\n";
158: close OUT;
159: }
160: open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");
161: print OUT $newpwd; print OUT "\n";
162: print OUT $newpwd; print OUT "\n";
163: close OUT;
164: $<=$wwwid; # unfool the program
165: &disable_root_capability;
166: unlink('/tmp/lock_lcpasswd');
167: exit 0;
168:
169: # ----------------------------------------------------------- have setuid script run as root
170: sub enable_root_capability {
171: if ($wwwid==$>) {
172: ($<,$>)=($>,$<);
173: ($(,$))=($),$();
174: }
175: else {
176: # root capability is already enabled
177: }
178: return $>;
179: }
180:
181: # ----------------------------------------------------------- have setuid script run as www
182: sub disable_root_capability {
183: if ($wwwid==$<) {
184: ($<,$>)=($>,$<);
185: ($(,$))=($),$();
186: }
187: else {
188: # root capability is already disabled
189: }
190: }
191:
192: # ----------------------------------- make sure that another lcpasswd process isn't running
193: sub try_to_lock {
194: my ($lockfile)=@_;
195: my $currentpid;
196: my $lastpid;
197: # Do not manipulate lock file as root
198: if ($>==0) {
199: return 0;
200: }
201: # Try to generate lock file.
202: # Wait 3 seconds. If same process id is in
203: # lock file, then assume lock file is stale, and
204: # go ahead. If process id's fluctuate, try
205: # for a maximum of 10 times.
206: for (0..10) {
207: if (-e $lockfile) {
208: open(LOCK,"<$lockfile");
209: $currentpid=<LOCK>;
210: close LOCK;
211: if ($currentpid==$lastpid) {
212: last;
213: }
214: sleep 3;
215: $lastpid=$currentpid;
216: }
217: else {
218: last;
219: }
220: if ($_==10) {
221: return 0;
222: }
223: }
224: open(LOCK,">$lockfile");
225: print LOCK $$;
226: close LOCK;
227: return 1;
228: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>