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