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