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