Annotation of loncom/lcnfson, revision 1.6

1.1       harris41    1: #!/usr/bin/perl
                      2: 
                      3: use strict;
                      4: 
1.6     ! foxr        5: # $Id: lcnfson,v 1.5 2007/08/22 19:53:22 albertel Exp $
1.5       albertel    6: 
1.3       harris41    7: # This script is a setuid script (chmod 6755; chown root:root).
                      8: # It enables nfs/portmap services for a specific user at
                      9: # a specific ip address.
                     10: 
                     11: # Exit codes.  0=ok.  Higher than 0 means something went wrong.
1.2       harris41   12: # Usage within code
                     13: #
                     14: # $exitcode=system("/home/httpd/perl/lcuseradd","NAME","IPADDRESS")/256;
                     15: # print "uh-oh" if $exitcode;
                     16: 
1.1       harris41   17: # Security
                     18: $ENV{'PATH'}=""; # Nullify path information.
                     19: $ENV{'BASH_ENV'}=""; # Nullify shell environment information.
                     20: 
                     21: # Do not print error messages if there are command-line arguments
                     22: my $noprint=0;
                     23: if (@ARGV) {
                     24:     $noprint=1;
                     25: }
                     26: 
                     27: # Read in /etc/passwd, and make sure this process is running from user=www
                     28: open (IN, "</etc/passwd");
                     29: my @lines=<IN>;
                     30: close IN;
                     31: my $wwwid;
                     32: for my $l (@lines) {
                     33:     chop $l;
                     34:     my @F=split(/\:/,$l);
                     35:     if ($F[0] eq 'www') {$wwwid=$F[2];}
                     36: }
                     37: if ($wwwid!=$<) {
                     38:     print("User ID mismatch.  This program must be run as user 'www'\n") unless $noprint;
                     39:     exit 1;
                     40: }
1.6     ! foxr       41: 
1.1       harris41   42: 
                     43: # Handle case of another lcnfs process
                     44: unless (&try_to_lock("/tmp/lock_lcnfs")) {
                     45:     print "Error. Too many other simultaneous nfs change requests being made.\n" unless $noprint;
                     46:     exit 4;
                     47: }
1.2       harris41   48: # Gather input.  Should be 2 values (user name, numeric ip address).
1.1       harris41   49: my @input;
                     50: if (@ARGV==3) {
                     51:     @input=@ARGV;
                     52: }
                     53: elsif (@ARGV) {
1.2       harris41   54:     print("Error. This program needs 2 command-line arguments (username, numeric ip address).\n") unless $noprint;
                     55:     unlink('/tmp/lock_lcnfs');
1.1       harris41   56:     exit 2;
                     57: }
                     58: else {
                     59:     @input=<>;
1.2       harris41   60:     if (@input!=2) {
                     61: 	print("Error. Two lines should be entered into standard input.\n") unless $noprint;
                     62: 	unlink('/tmp/lock_lcnfs');
1.1       harris41   63: 	exit 3;
                     64:     }
                     65:     map {chop} @input;
                     66: }
                     67: 
                     68: my ($username,$ipaddress)=@input;
                     69: $username=~/^(\w+)$/;
                     70: my $safeusername=$1;
                     71: if ($username ne $safeusername) {
                     72:     print "Error. The user name specified has invalid characters.\n";
1.2       harris41   73:     unlink('/tmp/lock_lcnfs');
1.1       harris41   74:     exit 9;
                     75: }
                     76: 
                     77: # Read in /etc/passwd, and make sure this process is running from user=www
                     78: open (IN, "</etc/passwd");
                     79: my @lines=<IN>;
                     80: close IN;
                     81: my $uid;
                     82: my $gid;
                     83: for my $l (@lines) {
                     84:     chop $l;
                     85:     my @F=split(/\:/,$l);
                     86:     if ($F[0] eq $safeusername) {$uid=$F[2]; $gid=$F[3];}
                     87: }
                     88: 
                     89: $ipaddress=~/^([\w|\.]*)$/;
                     90: my $safeipaddress=$1;
                     91: if ($ipaddress ne $safeipaddress) {
                     92:     print "Error. The IP address must be numeric and of the form ##.##.##.##.\n";
1.2       harris41   93:     unlink('/tmp/lock_lcnfs');
1.1       harris41   94:     exit 8;
                     95: }
                     96: 
                     97: &enable_root_capability;
                     98: # Make sure nfs is running, if not, start it
                     99: my $status=`/etc/rc.d/init.d/nfs status`;
                    100: if ($status=~/is stopped/) {
                    101:     system('/etc/rc.d/init.d/nfs start','start');
                    102: }
                    103: 
                    104: # Add entry to /etc/exports
                    105: my $exports=`/bin/cat /etc/exports`; $exports="\n$exports";
1.2       harris41  106: my $entry="/home/$safeusername     $safeipaddress(rw,all_squash,anonuid=$uid,anongid=$gid)\n";
1.1       harris41  107: if ($exports=~/\n\/home\/$safeusername\s+$safeipaddress\(rw,all_squash,anonuid=$uid,anongid=$gid\)/) {
                    108:     print "Error. /etc/exports already has this entry enabled.\n";
1.2       harris41  109:     unlink('/tmp/lock_lcnfs');
1.1       harris41  110:     exit 7;
                    111: }
1.2       harris41  112: open (OUT,">>/etc/exports");
1.1       harris41  113: print OUT $entry;
                    114: close OUT;
                    115: 
                    116: # Resynchronize /etc/exports file
                    117: system('/usr/sbin/exportfs','-r');
                    118: 
                    119: # Add entry /etc/hosts.allow
                    120: my $hostsallow=`/bin/cat /etc/hosts.allow`;
1.2       harris41  121: my $entry="# $safeusername\nportmap: $safeipaddress\n";
                    122: if ($hostsallow=~/\n\# $safeusername\s*\nportmap: $safeipaddress\n/) {
1.1       harris41  123:     print "Error. /etc/hosts already has this entry enabled.\n";
1.2       harris41  124:     unlink('/tmp/lock_lcnfs');
1.1       harris41  125:     exit 6;
                    126: }
                    127: open (OUT,">>/etc/hosts.allow");
                    128: print OUT $entry;
                    129: close OUT;
1.2       harris41  130: 
                    131: &disable_root_capability;
                    132: unlink('/tmp/lock_lcnfs');
                    133: exit 0;
1.1       harris41  134: 
                    135: # ----------------------------------------------------------- have setuid script run as root
                    136: sub enable_root_capability {
                    137:     if ($wwwid==$>) {
                    138: 	($<,$>)=($>,$<);
                    139: 	($(,$))=($),$();
                    140:     }
                    141:     else {
                    142: 	# root capability is already enabled
                    143:     }
                    144:     return $>;
                    145: }
                    146: 
                    147: # ----------------------------------------------------------- have setuid script run as www
                    148: sub disable_root_capability {
                    149:     if ($wwwid==$<) {
                    150: 	($<,$>)=($>,$<);
                    151: 	($(,$))=($),$();
                    152:     }
                    153:     else {
                    154: 	# root capability is already disabled
                    155:     }
                    156: }
                    157: 
                    158: # ----------------------------------- make sure that another lcnfs process isn't running
                    159: sub try_to_lock {
                    160:     my ($lockfile)=@_;
                    161:     my $currentpid;
                    162:     my $lastpid;
                    163:     # Do not manipulate lock file as root
                    164:     if ($>==0) {
                    165: 	return 0;
                    166:     }
                    167:     # Try to generate lock file.
                    168:     # Wait 3 seconds.  If same process id is in
                    169:     # lock file, then assume lock file is stale, and
                    170:     # go ahead.  If process id's fluctuate, try
                    171:     # for a maximum of 10 times.
                    172:     for (0..10) {
                    173: 	if (-e $lockfile) {
                    174: 	    open(LOCK,"<$lockfile");
                    175: 	    $currentpid=<LOCK>;
                    176: 	    close LOCK;
                    177: 	    if ($currentpid==$lastpid) {
                    178: 		last;
                    179: 	    }
                    180: 	    sleep 3;
                    181: 	    $lastpid=$currentpid;
                    182: 	}
                    183: 	else {
                    184: 	    last;
                    185: 	}
                    186: 	if ($_==10) {
                    187: 	    return 0;
                    188: 	}
                    189:     }
                    190:     open(LOCK,">$lockfile");
                    191:     print LOCK $$;
                    192:     close LOCK;
                    193:     return 1;
                    194: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>