Commit 24118cc5 authored by Dietmar Maurer's avatar Dietmar Maurer

add file upload hacks

parent 80bae398
...@@ -22,6 +22,10 @@ use JSON; ...@@ -22,6 +22,10 @@ use JSON;
@ISA = qw(HTTP::Daemon); @ISA = qw(HTTP::Daemon);
# DOS attack prevention
$CGI::DISABLE_UPLOADS = 1; # no uploads
$CGI::POST_MAX = 1024 * 10; # max 10K posts
my $documentroot = "/usr/share/pve-api/root"; my $documentroot = "/usr/share/pve-api/root";
my $workers = {}; my $workers = {};
...@@ -295,8 +299,9 @@ sub handle_requests { ...@@ -295,8 +299,9 @@ sub handle_requests {
my $clientip = $headers->header('PVEClientIP'); my $clientip = $headers->header('PVEClientIP');
my $res = PVE::REST::rest_handler($clientip, $method, $uri, $rel_uri, $rpcenv->init_request(params => $params);
$ticket, undef, $params);
my $res = PVE::REST::rest_handler($rpcenv, $clientip, $method, $uri, $rel_uri, $ticket);
if ($res->{proxy}) { if ($res->{proxy}) {
......
...@@ -8,7 +8,6 @@ use PVE::SafeSyslog; ...@@ -8,7 +8,6 @@ use PVE::SafeSyslog;
use PVE::Tools; use PVE::Tools;
use PVE::API2; use PVE::API2;
use Apache2::Const; use Apache2::Const;
use CGI;
use mod_perl2; use mod_perl2;
use JSON; use JSON;
use Digest::SHA; use Digest::SHA;
...@@ -285,15 +284,12 @@ my $check_permissions = sub { ...@@ -285,15 +284,12 @@ my $check_permissions = sub {
}; };
sub rest_handler { sub rest_handler {
my ($clientip, $method, $abs_uri, $rel_uri, $ticket, $token, $params) = @_; my ($rpcenv, $clientip, $method, $abs_uri, $rel_uri, $ticket, $token) = @_;
my $rpcenv = PVE::RPCEnvironment::get(); # set environment variables
$rpcenv->set_language('C'); # fixme:
eval { $rpcenv->init_request(); }; $rpcenv->set_client_ip($clientip);
if (my $err = $@) { $rpcenv->set_result_count(undef);
syslog('err', $err);
return { status => HTTP_INTERNAL_SERVER_ERROR, message => $err };
}
my $euid = $>; my $euid = $>;
...@@ -307,6 +303,8 @@ sub rest_handler { ...@@ -307,6 +303,8 @@ sub rest_handler {
my ($username, $age); my ($username, $age);
my $isUpload = 0;
if ($require_auth) { if ($require_auth) {
eval { eval {
...@@ -314,8 +312,23 @@ sub rest_handler { ...@@ -314,8 +312,23 @@ sub rest_handler {
($username, $age) = PVE::AccessControl::verify_ticket($ticket); ($username, $age) = PVE::AccessControl::verify_ticket($ticket);
$rpcenv->set_user($username);
if ($method eq 'POST' && $rel_uri =~ m|^/nodes/([^/]+)/storage/([^/]+)/upload$|) {
my ($node, $storeid) = ($1, $2);
my $perm = {
path => "/storage/$storeid",
privs => [ 'abc' ],
};
&$check_permissions($rpcenv, $perm, $username, {});
$isUpload = 1;
}
# we skip CSRF check for file upload, because it is
# difficult to pass CSRF HTTP headers with native html forms,
# and it should not be necessary at all.
PVE::AccessControl::verify_csrf_prevention_token($username, $token) PVE::AccessControl::verify_csrf_prevention_token($username, $token)
if ($euid != 0) && ($method ne 'GET'); if !$isUpload && ($euid != 0) && ($method ne 'GET');
}; };
if (my $err = $@) { if (my $err = $@) {
return { return {
...@@ -325,6 +338,8 @@ sub rest_handler { ...@@ -325,6 +338,8 @@ sub rest_handler {
} }
} }
# we are authenticated now
my $uri_param = {}; my $uri_param = {};
my ($handler, $info) = PVE::API2->find_handler($method, $rel_uri, $uri_param); my ($handler, $info) = PVE::API2->find_handler($method, $rel_uri, $uri_param);
if (!$handler || !$info) { if (!$handler || !$info) {
...@@ -334,6 +349,18 @@ sub rest_handler { ...@@ -334,6 +349,18 @@ sub rest_handler {
}; };
} }
# Note: we need to delay CGI parameter parsing until
# we are authenticated (avoid DOS (file upload) attacs)
my $params;
eval { $params = $rpcenv->parse_params($isUpload); };
if (my $err = $@) {
return {
status => HTTP_BAD_REQUEST,
message => "parameter parser failed: $err",
};
}
delete $params->{_dc}; # remove disable cache parameter delete $params->{_dc}; # remove disable cache parameter
foreach my $p (keys %{$params}) { foreach my $p (keys %{$params}) {
...@@ -362,8 +389,8 @@ sub rest_handler { ...@@ -362,8 +389,8 @@ sub rest_handler {
my $node = $uri_param->{$pn}; my $node = $uri_param->{$pn};
die "proxy parameter '$pn' does not exists" if !$node; die "proxy parameter '$pn' does not exists" if !$node;
if ($node ne 'localhost' && if ($node ne 'localhost' && $node ne PVE::INotify::nodename()) {
$node ne PVE::INotify::nodename()) { die "unable to proxy file uploads" if $isUpload;
$remip = PVE::Cluster::remote_node_ip($node); $remip = PVE::Cluster::remote_node_ip($node);
} }
}; };
...@@ -374,19 +401,17 @@ sub rest_handler { ...@@ -374,19 +401,17 @@ sub rest_handler {
}; };
} }
if ($remip) { if ($remip) {
return { proxy => $remip }; return { proxy => $remip, proxy_params => $params };
} }
} }
# fixme: not sure if we should do that here, because we can't proxy those if ($info->{protected} && ($euid != 0)) {
# methods to other hosts? if ($isUpload) {
return { proxy => 'localhost' } if $info->{protected} && ($euid != 0); my $uinfo = $rpcenv->get_upload_info('filename');
$params->{tmpfilename} = $uinfo->{tmpfilename};
# set environment variables }
$rpcenv->set_language('C'); # fixme: return { proxy => 'localhost' , proxy_params => $params }
$rpcenv->set_user($username); }
$rpcenv->set_client_ip($clientip);
$rpcenv->set_result_count(undef);
my $resp = { my $resp = {
info => $info, # useful to format output info => $info, # useful to format output
...@@ -451,10 +476,6 @@ sub handler { ...@@ -451,10 +476,6 @@ sub handler {
return HTTP_NOT_IMPLEMENTED return HTTP_NOT_IMPLEMENTED
if !$known_methods->{$method}; if !$known_methods->{$method};
my $cgi = CGI->new ($r);
my $params = $cgi->Vars();
my $cookie = $r->headers_in->{Cookie}; my $cookie = $r->headers_in->{Cookie};
my $token = $r->headers_in->{CSRFPreventionToken}; my $token = $r->headers_in->{CSRFPreventionToken};
...@@ -466,8 +487,20 @@ sub handler { ...@@ -466,8 +487,20 @@ sub handler {
my ($rel_uri, $format) = split_abs_uri($abs_uri); my ($rel_uri, $format) = split_abs_uri($abs_uri);
return HTTP_NOT_IMPLEMENTED if !$format; return HTTP_NOT_IMPLEMENTED if !$format;
my $res = rest_handler($clientip, $method, $abs_uri, $rel_uri, my $rpcenv;
$ticket, $token, $params); my $res;
eval {
$rpcenv = PVE::RPCEnvironment::get();
$rpcenv->init_request(request_rec => $r);
};
if (my $err = $@) {
syslog('err', $err);
$res = { status => HTTP_INTERNAL_SERVER_ERROR, message => $err };
} else {
$res = rest_handler($rpcenv, $clientip, $method, $abs_uri, $rel_uri,
$ticket, $token);
}
if ($res->{proxy}) { if ($res->{proxy}) {
if (($res->{proxy} ne 'localhost') && $r->headers_in->{'PVEDisableProxy'}) { if (($res->{proxy} ne 'localhost') && $r->headers_in->{'PVEDisableProxy'}) {
...@@ -477,7 +510,7 @@ sub handler { ...@@ -477,7 +510,7 @@ sub handler {
return $res->{status}; return $res->{status};
} }
return proxy_handler($r, $clientip, $res->{proxy}, $method, return proxy_handler($r, $clientip, $res->{proxy}, $method,
$abs_uri, $ticket, $token, $params); $abs_uri, $ticket, $token, $res->{proxy_params});
} }
prepare_response_data($format, $res); prepare_response_data($format, $res);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment