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