2 # Handles remote_* function calls by a faster method. When first called
3 # as a CGI, forks and starts listening on a port which is returned to the
4 # client. From then on, direct TCP connections can be made to this port
5 # to send requests and get replies.
7 BEGIN { push(@INC, ".."); };
11 $force_lang = $default_lang;
13 print "Content-type: text/plain\n\n";
15 # Can this user make remote calls?
16 %access = &get_module_acl();
17 if ($access{'rpc'} == 0 || $access{'rpc'} == 2 &&
18 $base_remote_user ne 'admin' && $base_remote_user ne 'root' &&
19 $base_remote_user ne 'sysadm') {
20 print "0 Invalid user for RPC\n";
25 &get_miniserv_config(\%miniserv);
26 $port = $miniserv{'port'} || 10000;
27 $aerr = &allocate_socket(MAIN, \$port);
32 if (open(RANDOM, "/dev/urandom")) {
34 read(RANDOM, $tmpsid, 16);
35 $sid = lc(unpack('h*', $tmpsid));
41 $version = &get_webmin_version();
42 print "1 $port $sid $version\n";
44 # Fork and listen for calls ..
47 die "fork() failed : $!";
55 # Accept the TCP connection
56 $acptaddr = accept(SOCK, MAIN);
57 die "accept failed!" if (!$acptaddr);
58 $oldsel = select(SOCK);
64 # Wait for the request. Wait longer if this isn't the first one
66 vec($rmask, fileno(SOCK), 1) = 1;
67 local $sel = select($rmask, undef, undef, $rcount ? 360 : 60);
69 print STDERR "fastrpc: session timed out\n"
70 if ($gconfig{'rpcdebug'});
76 local ($len, $auth) = split(/\s+/, $line);
77 die "Invalid session ID" if ($auth ne $sid);
79 while(length($rawarg) < $len) {
81 local $rv = read(SOCK, $got, $len - length($rawarg));
85 print STDERR "fastrpc: raw $rawarg\n" if ($gconfig{'rpcdebug'});
86 local $arg = &unserialise_variable($rawarg);
90 if ($arg->{'action'} eq 'ping') {
91 # Just respond with an OK
92 print STDERR "fastrpc: ping\n" if ($gconfig{'rpcdebug'});
93 $rawrv = &serialise_variable( { 'status' => 1 } );
95 elsif ($arg->{'action'} eq 'check') {
96 # Check if some module is supported
97 print STDERR "fastrpc: check $arg->{'module'}\n" if ($gconfig{'rpcdebug'});
98 $rawrv = &serialise_variable(
100 'rv' => &foreign_check($arg->{'module'}, undef, undef,
103 elsif ($arg->{'action'} eq 'config') {
104 # Get the config for some module
105 print STDERR "fastrpc: config $arg->{'module'}\n" if ($gconfig{'rpcdebug'});
106 local %config = &foreign_config($arg->{'module'});
107 $rawrv = &serialise_variable(
108 { 'status' => 1, 'rv' => \%config } );
110 elsif ($arg->{'action'} eq 'write') {
111 # Transfer data to a local temp file
112 local $file = $arg->{'file'} ? $arg->{'file'} :
113 $arg->{'name'} ? &tempname($arg->{'name'}) :
115 print STDERR "fastrpc: write $file\n" if ($gconfig{'rpcdebug'});
116 open(FILE, ">$file");
118 print FILE $arg->{'data'};
120 $rawrv = &serialise_variable(
121 { 'status' => 1, 'rv' => $file } );
123 elsif ($arg->{'action'} eq 'tcpwrite') {
124 # Transfer data to a local temp file over TCP connection
125 local $file = $arg->{'file'} ? $arg->{'file'} :
126 $arg->{'name'} ? &tempname($arg->{'name'}) :
128 print STDERR "fastrpc: tcpwrite $file\n" if ($gconfig{'rpcdebug'});
129 local $tsock = time().$$;
130 local $tport = $port + 1;
131 &allocate_socket($tsock, \$tport);
133 # Accept connection in separate process
134 print STDERR "fastrpc: tcpwrite $file port $tport\n" if ($gconfig{'rpcdebug'});
136 vec($rmask, fileno($tsock), 1) = 1;
137 local $sel = select($rmask, undef, undef, 30);
139 accept(TRANS, $tsock) || exit;
140 print STDERR "fastrpc: tcpwrite $file accepted\n" if ($gconfig{'rpcdebug'});
143 if (open(FILE, ">$file")) {
145 print STDERR "fastrpc: tcpwrite $file writing\n" if ($gconfig{'rpcdebug'});
146 while(read(TRANS, $buf, 1024) > 0) {
147 local $ok = (print FILE $buf);
149 $err = "Write to $file failed : $!";
154 print STDERR "fastrpc: tcpwrite $file written\n" if ($gconfig{'rpcdebug'});
157 print STDERR "fastrpc: tcpwrite $file open failed $!\n" if ($gconfig{'rpcdebug'});
158 $err = "Failed to open $file : $!";
160 print TRANS $err ? "$err\n" : "OK\n";
165 print STDERR "fastrpc: tcpwrite $file done\n" if ($gconfig{'rpcdebug'});
166 $rawrv = &serialise_variable(
167 { 'status' => 1, 'rv' => [ $file, $tport ] } );
169 elsif ($arg->{'action'} eq 'read') {
170 # Transfer data from a file
171 print STDERR "fastrpc: read $arg->{'file'}\n" if ($gconfig{'rpcdebug'});
173 open(FILE, $arg->{'file'});
175 while(read(FILE, $got, 1024) > 0) {
179 $rawrv = &serialise_variable(
180 { 'status' => 1, 'rv' => $data } );
182 elsif ($arg->{'action'} eq 'tcpread') {
183 # Transfer data from a file over TCP connection
184 print STDERR "fastrpc: tcpread $arg->{'file'}\n" if ($gconfig{'rpcdebug'});
185 if (!open(FILE, $arg->{'file'})) {
186 $rawrv = &serialise_variable(
187 { 'status' => 1, 'rv' => [ undef, "Failed to open $arg->{'file'} : $!" ] } );
191 local $tsock = time().$$;
192 local $tport = $port + 1;
193 &allocate_socket($tsock, \$tport);
195 # Accept connection in separate process
197 vec($rmask, fileno($tsock), 1) = 1;
198 local $sel = select($rmask, undef, undef, 30);
200 accept(TRANS, $tsock) || exit;
202 while(read(FILE, $buf, 1024) > 0) {
211 print STDERR "fastrpc: tcpread $arg->{'file'} done\n" if ($gconfig{'rpcdebug'});
212 $rawrv = &serialise_variable(
213 { 'status' => 1, 'rv' => [ $arg->{'file'}, $tport ] } );
216 elsif ($arg->{'action'} eq 'require') {
218 print STDERR "fastrpc: require $arg->{'module'}/$arg->{'file'}\n" if ($gconfig{'rpcdebug'});
220 &foreign_require($arg->{'module'},
224 print STDERR "fastrpc: require error $@\n" if ($gconfig{'rpcdebug'});
225 $rawrv = &serialise_variable( { 'status' => 0,
229 print STDERR "fastrpc: require done\n" if ($gconfig{'rpcdebug'});
230 $rawrv = &serialise_variable( { 'status' => 1 });
233 elsif ($arg->{'action'} eq 'call') {
235 print STDERR "fastrpc: call $arg->{'module'}::$arg->{'func'}(",join(",", @{$arg->{'args'}}),")\n" if ($gconfig{'rpcdebug'});
238 local $main::error_must_die = 1;
239 @rv = &foreign_call($arg->{'module'},
244 print STDERR "fastrpc: call error $@\n" if ($gconfig{'rpcdebug'});
245 $rawrv = &serialise_variable(
246 { 'status' => 0, 'rv' => $@ } );
249 $rawrv = &serialise_variable(
250 { 'status' => 1, 'rv' => $rv[0] } );
253 $rawrv = &serialise_variable(
254 { 'status' => 1, 'arv' => \@rv } );
256 print STDERR "fastrpc: call $arg->{'module'}::$arg->{'func'} done = ",join(",", @rv),"\n" if ($gconfig{'rpcdebug'});
258 elsif ($arg->{'action'} eq 'eval') {
259 # eval some perl code
260 print STDERR "fastrpc: eval $arg->{'module'} $arg->{'code'}\n" if ($gconfig{'rpcdebug'});
262 if ($arg->{'module'}) {
263 local $pkg = $arg->{'module'};
264 $pkg =~ s/[^A-Za-z0-9]/_/g;
265 $rv = eval "package $pkg;\n".
269 $rv = eval $arg->{'code'};
271 print STDERR "fastrpc: eval $arg->{'module'} $arg->{'code'} done = $rv error = $@\n" if ($gconfig{'rpcdebug'});
273 $rawrv = &serialise_variable(
274 { 'status' => 0, 'rv' => $@ } );
277 $rawrv = &serialise_variable(
278 { 'status' => 1, 'rv' => $rv } );
281 elsif ($arg->{'action'} eq 'quit') {
282 print STDERR "fastrpc: quit\n" if ($gconfig{'rpcdebug'});
283 $rawrv = &serialise_variable( { 'status' => 1 } );
286 print STDERR "fastrpc: unknown $arg->{'action'}\n" if ($gconfig{'rpcdebug'});
287 $rawrv = &serialise_variable( { 'status' => 0 } );
290 # Send back to the client
291 print SOCK length($rawrv),"\n";
293 last if ($arg->{'action'} eq 'quit');
297 # allocate_socket(handle, &port)
300 local ($fh, $port) = @_;
301 local $proto = getprotobyname('tcp');
302 if (!socket($fh, PF_INET, SOCK_STREAM, $proto)) {
303 return "socket failed : $!";
305 setsockopt($fh, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));
308 last if (bind($fh, sockaddr_in($$port, INADDR_ANY)));
310 listen($fh, SOMAXCONN);