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