Annotation of loncom/lcnfson, revision 1.3

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

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