Handle hostnames with upper-case letters
[webmin.git] / rpc.cgi
1 #!/usr/local/bin/perl
2 # rpc.cgi
3 # Handles remote_foreign_require and remote_foreign_call requests from
4 # other webmin servers. State is preserved by starting a process for each
5 # session that listens for requests on a named pipe (and dies after a few
6 # seconds of inactivity)
7 # access{'rpc'}  0=not allowed 1=allowed 2=allowed if root or admin
8
9 BEGIN { push(@INC, ".."); };
10 use WebminCore;
11 use POSIX;
12
13 &init_config();
14 if ($ENV{'REQUEST_METHOD'} eq 'POST') {
15         local $got;
16         local $left = $ENV{'CONTENT_LENGTH'} - length($rawarg);
17         while($left > 0) {
18                 read(STDIN, $got, $left) > 0 || last;
19                 $rawarg .= $got;
20                 $left = $ENV{'CONTENT_LENGTH'} - length($rawarg);
21                 }
22         }
23 else {
24         $rawarg = $ENV{'QUERY_STRING'};
25         }
26 $arg = &unserialise_variable($rawarg);
27 $| = 1;
28 print "Content-type: text/plain\n\n";
29
30 # Can this user make remote calls?
31 %access = &get_module_acl();
32 if ($access{'rpc'} == 0 || $access{'rpc'} == 2 &&
33     $base_remote_user ne 'admin' && $base_remote_user ne 'root' &&
34     $base_remote_user ne 'sysadm') {
35         print &serialise_variable( { 'status' => 0 } );
36         exit;
37         }
38
39 if ($arg->{'newsession'}) {
40         # Need to fork a new session-handler process
41         $fifo1 = &tempname();
42         $fifo2 = &tempname();
43         mkfifo($fifo1, 0700);
44         mkfifo($fifo2, 0700);
45         if (!fork()) {
46                 # This is the subprocess where execution really happens
47                 $SIG{'ALRM'} = "fifo_timeout";
48                 untie(*STDIN);
49                 untie(*STDOUT);
50                 close(STDIN);
51                 close(STDOUT);
52                 close(miniserv::SOCK);
53                 local $stime = time();
54                 local $rcount = 0;
55                 while(1) {
56                         local ($rawcmd, $cmd, @rv);
57                         alarm($rcount ? 360 : 60);
58                         open(FIFO, $fifo1) || last;
59                         while(<FIFO>) {
60                                 $rawcmd .= $_;
61                                 }
62                         close(FIFO);
63                         alarm(0);
64                         $cmd = &unserialise_variable($rawcmd);
65                         if ($cmd->{'action'} eq 'quit') {
66                                 # time to end this session (after the reply)
67                                 @rv = ( { 'time' => time() - $stime } );
68                                 }
69                         elsif ($cmd->{'action'} eq 'require') {
70                                 # require a library
71                                 &foreign_require($cmd->{'module'},
72                                                  $cmd->{'file'});
73                                 @rv = ( { 'session' => [ $fifo1, $fifo2 ] } );
74                                 }
75                         elsif ($cmd->{'action'} eq 'call') {
76                                 # execute a function
77                                 @rv = &foreign_call($cmd->{'module'},
78                                                     $cmd->{'func'},
79                                                     @{$cmd->{'args'}});
80                                 }
81                         elsif ($cmd->{'action'} eq 'eval') {
82                                 # eval some perl code
83                                 if ($cmd->{'module'}) {
84                                         @rv = eval <<EOF;
85 package $cmd->{'module'};
86 $cmd->{'code'}
87 EOF
88                                         }
89                                 else {
90                                         @rv = eval $cmd->{'code'};
91                                         }
92                                 }
93                         open(FIFO, ">$fifo2");
94                         if (@rv == 1) {
95                                 print FIFO &serialise_variable(
96                                         { 'status' => 1, 'rv' => $rv[0] } );
97                                 }
98                         else {
99                                 print FIFO &serialise_variable(
100                                         { 'status' => 1, 'arv' => \@rv } );
101                                 }
102                         close(FIFO);
103                         last if ($cmd->{'action'} eq 'quit');
104                         $rcount++;
105                         }
106                 unlink($fifo1);
107                 unlink($fifo2);
108                 exit;
109                 }
110         $session = [ $fifo1, $fifo2 ];
111         }
112 else {
113         # Use the provided session id
114         $session = $arg->{'session'};
115         }
116
117 if ($arg->{'action'} eq 'ping') {
118         # Just respond with an OK
119         print &serialise_variable( { 'status' => 1 } );
120         }
121 elsif ($arg->{'action'} eq 'check') {
122         # Check if some module is supported
123         print &serialise_variable(
124                 { 'status' => 1,
125                   'rv' => &foreign_check($arg->{'module'}, undef, undef,
126                                          $arg->{'api'}) } );
127         }
128 elsif ($arg->{'action'} eq 'config') {
129         # Get the config for some module
130         local %config = &foreign_config($arg->{'module'});
131         print &serialise_variable(
132                 { 'status' => 1, 'rv' => \%config } );
133         }
134 elsif ($arg->{'action'} eq 'write') {
135         # Transfer data to a local temp file
136         local $file = $arg->{'file'} ? $arg->{'file'} :
137                       $arg->{'name'} ? &tempname($arg->{'name'}) :
138                                        &tempname();
139         open(FILE, ">$file");
140         print FILE $arg->{'data'};
141         close(FILE);
142         print &serialise_variable(
143                 { 'status' => 1, 'rv' => $file } );
144         }
145 elsif ($arg->{'action'} eq 'read') {
146         # Transfer data from a file
147         local ($data, $got);
148         open(FILE, $arg->{'file'});
149         while(read(FILE, $got, 1024) > 0) {
150                 $data .= $got;
151                 }
152         close(FILE);
153         print &serialise_variable(
154                 { 'status' => 1, 'rv' => $data } );
155         }
156 else {
157         # Pass the request on to the subprocess
158         open(FIFO, ">$session->[0]");
159         print FIFO $rawarg;
160         close(FIFO);
161         open(FIFO, $session->[1]);
162         while(<FIFO>) {
163                 print;
164                 }
165         close(FIFO);
166         }
167
168 sub fifo_timeout
169 {
170 unlink($fifo1);
171 unlink($fifo2);
172 exit;
173 }
174