Annotation of loncom/lcpasswd, revision 1.3
1.1 harris41 1: #!/usr/bin/perl
1.3 ! harris41 2: #
! 3: # lcpasswd
! 4: #
! 5: # Scott Harrison
! 6: # October 27, 2000
1.1 harris41 7:
8: use strict;
9:
10: # This script is a setuid script that should
11: # be run by user 'www'.
12:
13: # Standard input usage
14: # First line is USERNAME
15: # Second line is CURRENT PASSWORD
16: # Third line is NEW PASSWORD
17:
18: # Security
1.2 harris41 19: $ENV{'PATH'}="/bin:/usr/bin"; # Nullify path information except for what smbpasswd needs
1.1 harris41 20: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
21:
22: open (IN, "</etc/passwd");
23: my @lines=<IN>;
24: close IN;
25: my $wwwid;
26: for my $l (@lines) {
27: chop $l;
28: my @F=split(/\:/,$l);
29: if ($F[0] eq 'www') {$wwwid=$F[2];}
30: }
31: if ($wwwid!=$<) {
32: print("User ID mismatch. This program must be run as user 'www'\n");
33: exit 0;
34: }
1.2 harris41 35: &disable_root_capability;
1.1 harris41 36: if (@ARGV) {
37: print("Error. This program does not accept command-line arguments.\n");
38: exit 0;
39: }
40:
41: # Gather input from standard input. Should only be 3 lines.
42: my @input=<>;
43: if (@input!=3) {
44: print("Error. Three lines need to be entered into standard input.\n");
45: exit 0;
46: }
47:
48: # Handle case of another lcpasswd process
49: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
50: print "Error. Too many other simultaneous password change requests being made.\n";
51: exit 0;
52: }
53:
54: my ($username,$oldpwd,$newpwd)=map {chop; $_} @input;
55:
56: # Grab the line corresponding to username
57: my ($userid,$useroldcryptpwd);
58: my @F; my @U;
59: for my $l (@lines) {
60: @F=split(/\:/,$l);
61: if ($F[0] eq $username) {($userid,$useroldcryptpwd)=($F[2],$F[1]); @U=@F;}
62: }
63:
64: # Verify existence of user
65: if (!defined($userid)) {
66: print "Error. User $username does not exist.\n";
67: exit 0;
68: }
69:
70: # Verify password entry
71: if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {
72: print "Error. Invalid entry of current password.\n";
73: exit 0;
74: }
75:
1.2 harris41 76: # Construct new password entry (random salt)
77: my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
1.1 harris41 78: $U[1]=$newcryptpwd;
79: my $userline=join(":",@U);
1.2 harris41 80: my $rootid=&enable_root_capability;
81: if ($rootid!=0) {
82: print "Error. Root was not successfully enabled.\n";
83: exit 0;
84: }
85: open PASSWORDFILE, ">/etc/passwd" or die("Cannot open /etc/passwd!");
1.1 harris41 86: for my $l (@lines) {
87: @F=split(/\:/,$l);
88: if ($F[0] eq $username) {print PASSWORDFILE "$userline\n";}
89: else {print PASSWORDFILE "$l\n";}
90: }
91: close PASSWORDFILE;
1.2 harris41 92: $username=~/^(\w+)$/;
93: my $safeusername=$1;
94: ($>,$<)=(0,0); # fool smbpasswd here to think this is not a setuid environment
95: unless (-e "/etc/smbpasswd") {
96: open (OUT,">/etc/smbpasswd"); close OUT;
97: }
98: my $smbexist=0;
99: open (IN, "</etc/smbpasswd");
100: my @lines=<IN>;
101: close IN;
102: for my $l (@lines) {
103: chop $l;
104: my @F=split(/\:/,$l);
105: if ($F[0] eq $username) {$smbexist=1;}
106: }
107: unless ($smbexist) {
108: open(OUT,">>/etc/smbpasswd");
109: print OUT join(":",($safeusername,$userid,'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX','','/home/'.$safeusername,'/bin/bash')) . "\n";
110: close OUT;
111: }
112: open(OUT,"|/usr/bin/smbpasswd -s $safeusername>/dev/null");
113: print OUT $newpwd; print OUT "\n";
114: print OUT $newpwd; print OUT "\n";
115: close OUT;
116: $<=$wwwid; # unfool the program
1.1 harris41 117: &disable_root_capability;
118: unlink("/tmp/lock_lcpasswd");
119:
120: sub enable_root_capability {
1.2 harris41 121: if ($wwwid==$>) {
1.1 harris41 122: ($<,$>)=($>,$<);
123: ($(,$))=($),$();
124: }
125: else {
126: # root capability is already enabled
127: }
1.2 harris41 128: return $>;
1.1 harris41 129: }
130:
131: sub disable_root_capability {
1.2 harris41 132: if ($wwwid==$<) {
1.1 harris41 133: ($<,$>)=($>,$<);
134: ($(,$))=($),$();
135: }
136: else {
137: # root capability is already disabled
138: }
139: }
140:
141: sub try_to_lock {
142: my ($lockfile)=@_;
143: my $currentpid;
144: my $lastpid;
145: for (0..10) {
146: if (-e $lockfile) {
147: open(LOCK,"<$lockfile");
148: $currentpid=<LOCK>;
149: close LOCK;
150: if ($currentpid==$lastpid) {
151: last;
152: }
153: sleep 3;
154: $lastpid=$currentpid;
155: }
156: else {
157: last;
158: }
159: if ($_==10) {
160: return 0;
161: }
162: }
163: open(LOCK,">$lockfile");
164: print LOCK $$;
165: close LOCK;
166: return 1;
167: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>