File:
[LON-CAPA] /
loncom /
lcpasswd
Revision
1.4:
download - view:
text,
annotated -
select for diffs
Fri Oct 27 23:32:24 2000 UTC (23 years, 11 months ago) by
harris41
Branches:
MAIN
CVS tags:
HEAD
allow for command-line arguments in order to enable use
within other scripts (so they can read exit status);
disable error message printing when command-line arguments
are given
1: #!/usr/bin/perl
2: #
3: # lcpasswd
4: #
5: # Scott Harrison
6: # October 27, 2000
7:
8: use strict;
9:
10: # This script is a setuid script that should
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.
15:
16: # Standard input usage
17: # First line is USERNAME
18: # Second line is CURRENT PASSWORD
19: # Third line is NEW PASSWORD
20:
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:
41: # Security
42: $ENV{'PATH'}="/bin:/usr/bin"; # Nullify path information except for what smbpasswd needs
43: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
44:
45: # Do not print error messages if there are command-line arguments
46: my $noprint=0;
47: if (@ARGV) {
48: $noprint=1;
49: }
50:
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!=$<) {
61: print("User ID mismatch. This program must be run as user 'www'\n") unless $noprint;
62: exit 1;
63: }
64: &disable_root_capability;
65:
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;
82: }
83: # Handle case of another lcpasswd process
84: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
85: print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;
86: exit 4;
87: }
88:
89: my ($username,$oldpwd,$newpwd)=@input;
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)) {
101: print "Error. User $username does not exist.\n" unless $noprint;
102: unlink("/tmp/lock_lcpasswd");
103: exit 5;
104: }
105:
106: # Verify password entry
107: if (crypt($oldpwd,$useroldcryptpwd) ne $useroldcryptpwd) {
108: print "Error. Invalid entry of current password.\n" unless $noprint;
109: unlink("/tmp/lock_lcpasswd");
110: exit 6;
111: }
112:
113: # Construct new password entry (random salt)
114: my $newcryptpwd=crypt($newpwd,(join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]));
115: $U[1]=$newcryptpwd;
116: my $userline=join(":",@U);
117: my $rootid=&enable_root_capability;
118: if ($rootid!=0) {
119: print "Error. Root was not successfully enabled.\n" unless $noprint;
120: unlink("/tmp/lock_lcpasswd");
121: exit 7;
122: }
123: open PASSWORDFILE, ">/etc/passwd" or die("Cannot open /etc/passwd!");
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;
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
155: &disable_root_capability;
156: unlink("/tmp/lock_lcpasswd");
157: exit 0;
158:
159: # ----------------------------------------------------------- have setuid script run as root
160: sub enable_root_capability {
161: if ($wwwid==$>) {
162: ($<,$>)=($>,$<);
163: ($(,$))=($),$();
164: }
165: else {
166: # root capability is already enabled
167: }
168: return $>;
169: }
170:
171: # ----------------------------------------------------------- have setuid script run as www
172: sub disable_root_capability {
173: if ($wwwid==$<) {
174: ($<,$>)=($>,$<);
175: ($(,$))=($),$();
176: }
177: else {
178: # root capability is already disabled
179: }
180: }
181:
182: # ----------------------------------- make sure that another lcpasswd process isn't running
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>