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>