Annotation of loncom/lcuserdel, revision 1.14
1.1 harris41 1: #!/usr/bin/perl
2: #
3: # lcuserdel
4: #
5: # Scott Harrison
1.4 harris41 6: # SH: October 27, 2000
7: # SH: October 28, 2000
1.5 harris41 8: # SH: October 29, 2000
1.1 harris41 9:
10: use strict;
11:
1.2 harris41 12: # This script is a setuid script (chmod 6755) that should
1.1 harris41 13: # be run by user 'www'. It DOES NOT delete directories.
14: # All it does is remove a user's entries from
15: # /etc/passwd, /etc/groups, and /etc/smbpasswd.
1.5 harris41 16: # It also disables user directory access by making the directory
17: # to be owned by user=www (as opposed to the former "username").
18: # This command only returns an error if it is
19: # invoked incorrectly (by passing bad command-line arguments, etc).
1.1 harris41 20:
1.3 harris41 21: # This script works under the same process control mechanism
22: # as lcuseradd and lcpasswd, to make sure that only one of these
23: # processes is running at any one time on the system.
1.1 harris41 24:
25: # Standard input usage
26: # First line is USERNAME
27:
1.10 harris41 28: # Valid user names must consist of ascii
29: # characters that are alphabetical characters
30: # (A-Z,a-z), numeric (0-9), or the underscore
31: # mark (_). (Essentially, the perl regex \w).
32:
1.1 harris41 33: # Command-line arguments [USERNAME]
34: # Yes, but be very careful here (don't pass shell commands)
35: # and this is only supported to allow perl-system calls.
36:
1.2 harris41 37: # Usage within code
38: #
1.3 harris41 39: # $exitcode=system("/home/httpd/perl/lcuserdel","NAME")/256;
1.2 harris41 40: # print "uh-oh" if $exitcode;
41:
42: # These are the exit codes.
1.9 harris41 43: # ( (0,"ok"),
44: # (1,"User ID mismatch. This program must be run as user 'www'"),
1.11 harris41 45: # (2,"Error. This program needs just 1 command-line argument (username).") )
1.9 harris41 46: # (3,"Error. Only one line should be entered into standard input."),
1.11 harris41 47: # (4,"Error. Too many other simultaneous password change requests being made."),
48: # (5,"Error. The user name specified has invalid characters.") )
1.2 harris41 49:
1.1 harris41 50: # Security
51: $ENV{'PATH'}=""; # Nullify path information.
52: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
1.2 harris41 53:
54: # Do not print error messages if there are command-line arguments
55: my $noprint=0;
56: if (@ARGV) {
57: $noprint=1;
58: }
59:
1.3 harris41 60: # Read in /etc/passwd, and make sure this process is running from user=www
1.2 harris41 61: open (IN, "</etc/passwd");
62: my @lines=<IN>;
63: close IN;
64: my $wwwid;
65: for my $l (@lines) {
66: chop $l;
67: my @F=split(/\:/,$l);
68: if ($F[0] eq 'www') {$wwwid=$F[2];}
69: }
70: if ($wwwid!=$<) {
71: print("User ID mismatch. This program must be run as user 'www'\n") unless $noprint;
72: exit 1;
73: }
74: &disable_root_capability;
75:
1.3 harris41 76: # Handle case of another lcpasswd process
77: unless (&try_to_lock("/tmp/lock_lcpasswd")) {
78: print "Error. Too many other simultaneous password change requests being made.\n" unless $noprint;
79: exit 4;
80: }
81:
82: # Gather input. Should only be 1 value (user name).
1.2 harris41 83: my @input;
1.3 harris41 84: if (@ARGV==1) {
1.2 harris41 85: @input=@ARGV;
86: }
87: elsif (@ARGV) {
1.3 harris41 88: print("Error. This program needs just 1 command-line argument (username).\n") unless $noprint;
1.9 harris41 89: unlink('/tmp/lock_lcpasswd');
1.2 harris41 90: exit 2;
91: }
92: else {
93: @input=<>;
1.3 harris41 94: if (@input!=1) {
95: print("Error. Only one line should be entered into standard input.\n") unless $noprint;
1.9 harris41 96: unlink('/tmp/lock_lcpasswd');
1.2 harris41 97: exit 3;
98: }
99: map {chop} @input;
100: }
1.4 harris41 101:
102: my ($username)=@input;
103: $username=~/^(\w+)$/;
104: my $safeusername=$1;
1.10 harris41 105: if ($username ne $safeusername) {
106: print "Error. The user name specified has invalid characters.\n";
107: unlink('/tmp/lock_lcpasswd');
1.11 harris41 108: exit 5;
1.10 harris41 109: }
1.4 harris41 110:
1.5 harris41 111: &enable_root_capability;
112:
1.4 harris41 113: # By using the system userdel command:
114: # Remove entry from /etc/passwd if it exists
115: # Remove entry from /etc/groups if it exists
1.8 harris41 116: # I surround with groupdel command to make absolutely sure the group definition disappears.
1.12 harris41 117: system('/usr/sbin/groupdel',$safeusername); # ignore error message
118: system('/usr/sbin/userdel',$safeusername); # ignore error message
119: system('/usr/sbin/groupdel',$safeusername); # ignore error message
1.4 harris41 120:
121: # Remove entry from /etc/smbpasswd if it exists
1.13 foxr 122: # the safest way to do this is with smbpasswd -x
123: # as that's independent of location of the smbpasswd file.
124: #
125: if (-e '/usr/bin/smbpasswd') {
126: ($>,$<) = (0,0); # fool smbpasswd to think this is not setuid.
127: system('/usr/bin/smbpasswd -x '.$safeusername);
1.14 ! foxr 128: $< = $wwwid;
1.13 foxr 129: }
1.4 harris41 130:
131:
132: # Change ownership on directory from username:username to www:www
133: # This prevents subsequently added users from having access.
134:
1.5 harris41 135: system('/bin/chown','-R','www:www',"/home/$safeusername");
1.3 harris41 136:
137: &disable_root_capability;
138: unlink("/tmp/lock_lcpasswd");
139: exit 0;
140:
141: # ----------------------------------------------------------- have setuid script run as root
142: sub enable_root_capability {
143: if ($wwwid==$>) {
144: ($<,$>)=($>,$<);
145: ($(,$))=($),$();
146: }
147: else {
148: # root capability is already enabled
149: }
150: return $>;
151: }
152:
153: # ----------------------------------------------------------- have setuid script run as www
154: sub disable_root_capability {
155: if ($wwwid==$<) {
156: ($<,$>)=($>,$<);
157: ($(,$))=($),$();
158: }
159: else {
160: # root capability is already disabled
161: }
1.2 harris41 162: }
163:
1.3 harris41 164: # ----------------------------------- make sure that another lcpasswd process isn't running
165: sub try_to_lock {
166: my ($lockfile)=@_;
167: my $currentpid;
168: my $lastpid;
169: # Do not manipulate lock file as root
170: if ($>==0) {
171: return 0;
172: }
173: # Try to generate lock file.
174: # Wait 3 seconds. If same process id is in
175: # lock file, then assume lock file is stale, and
176: # go ahead. If process id's fluctuate, try
177: # for a maximum of 10 times.
178: for (0..10) {
179: if (-e $lockfile) {
180: open(LOCK,"<$lockfile");
181: $currentpid=<LOCK>;
182: close LOCK;
183: if ($currentpid==$lastpid) {
184: last;
185: }
186: sleep 3;
187: $lastpid=$currentpid;
188: }
189: else {
190: last;
191: }
192: if ($_==10) {
193: return 0;
194: }
195: }
196: open(LOCK,">$lockfile");
197: print LOCK $$;
198: close LOCK;
199: return 1;
200: }
1.2 harris41 201:
1.1 harris41 202:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>