mirror of
https://github.com/OpenNebula/one.git
synced 2026-11-16 01:33:10 +09:00
707 lines
19 KiB
C++
707 lines
19 KiB
C++
/* -------------------------------------------------------------------------- */
|
|
/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */
|
|
/* */
|
|
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
|
/* not use this file except in compliance with the License. You may obtain */
|
|
/* a copy of the License at */
|
|
/* */
|
|
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
|
/* */
|
|
/* Unless required by applicable law or agreed to in writing, software */
|
|
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
|
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
|
/* See the License for the specific language governing permissions and */
|
|
/* limitations under the License. */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
#include "Request.h"
|
|
#include "Nebula.h"
|
|
|
|
#include "PoolObjectAuth.h"
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::execute(
|
|
xmlrpc_c::paramList const& _paramList,
|
|
xmlrpc_c::value * const _retval)
|
|
{
|
|
RequestAttributes att;
|
|
|
|
att.retval = _retval;
|
|
att.session = xmlrpc_c::value_string (_paramList.getString(0));
|
|
|
|
att.req_id = (reinterpret_cast<uintptr_t>(this) * rand()) % 10000;
|
|
|
|
Nebula& nd = Nebula::instance();
|
|
UserPool* upool = nd.get_upool();
|
|
|
|
bool authenticated = upool->authenticate( att.session,
|
|
att.uid,
|
|
att.gid,
|
|
att.uname,
|
|
att.gname,
|
|
att.group_ids);
|
|
|
|
log_method_invoked(att, _paramList);
|
|
|
|
if ( authenticated == false )
|
|
{
|
|
failure_response(AUTHENTICATION, authenticate_error(), att);
|
|
}
|
|
else
|
|
{
|
|
request_execute(_paramList, att);
|
|
}
|
|
|
|
log_result(att);
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::log_method_invoked(
|
|
const RequestAttributes& att,
|
|
const xmlrpc_c::paramList& paramList)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Req:" << att.req_id << " UID:";
|
|
|
|
if ( att.uid != -1 )
|
|
{
|
|
oss << att.uid;
|
|
}
|
|
else
|
|
{
|
|
oss << "-";
|
|
}
|
|
|
|
oss << " " << method_name << " invoked";
|
|
|
|
for (unsigned int i=1; i<paramList.size(); i++)
|
|
{
|
|
log_xmlrpc_param(paramList[i], oss, i);
|
|
}
|
|
|
|
NebulaLog::log("ReM",Log::DEBUG, oss);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::log_result(
|
|
const RequestAttributes& att)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "Req:" << att.req_id << " UID:";
|
|
|
|
if ( att.uid != -1 )
|
|
{
|
|
oss << att.uid;
|
|
}
|
|
else
|
|
{
|
|
oss << "-";
|
|
}
|
|
|
|
oss << " " << method_name << " result ";
|
|
|
|
xmlrpc_c::value_array array1(*att.retval);
|
|
vector<xmlrpc_c::value> const vvalue(array1.vectorValueValue());
|
|
|
|
if ( static_cast<bool>(xmlrpc_c::value_boolean(vvalue[0])) )
|
|
{
|
|
oss << "SUCCESS";
|
|
|
|
for (unsigned int i=1; i<vvalue.size()-1; i++)
|
|
{
|
|
log_xmlrpc_value(vvalue[i], oss);
|
|
}
|
|
|
|
NebulaLog::log("ReM",Log::DEBUG, oss);
|
|
}
|
|
else
|
|
{
|
|
oss << "FAILURE "
|
|
<< static_cast<string>(xmlrpc_c::value_string(vvalue[1]));
|
|
|
|
NebulaLog::log("ReM",Log::ERROR, oss);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::log_xmlrpc_param(
|
|
const xmlrpc_c::value& v,
|
|
ostringstream& oss,
|
|
const int& index)
|
|
{
|
|
log_xmlrpc_value(v, oss);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::log_xmlrpc_value(
|
|
const xmlrpc_c::value& v,
|
|
ostringstream& oss)
|
|
{
|
|
size_t st_limit = 20;
|
|
size_t st_newline;
|
|
|
|
switch (v.type())
|
|
{
|
|
case xmlrpc_c::value::TYPE_INT:
|
|
oss << ", " << static_cast<int>(xmlrpc_c::value_int(v));
|
|
break;
|
|
case xmlrpc_c::value::TYPE_BOOLEAN:
|
|
oss << ", ";
|
|
|
|
if ( static_cast<bool>(xmlrpc_c::value_boolean(v)) )
|
|
{
|
|
oss << "true";
|
|
}
|
|
else
|
|
{
|
|
oss << "false";
|
|
}
|
|
|
|
break;
|
|
case xmlrpc_c::value::TYPE_STRING:
|
|
st_newline =
|
|
static_cast<string>(xmlrpc_c::value_string(v)).find("\n");
|
|
|
|
if ( st_newline < st_limit )
|
|
{
|
|
st_limit = st_newline;
|
|
}
|
|
|
|
oss << ", \"" <<
|
|
static_cast<string>(xmlrpc_c::value_string(v)).substr(0,st_limit);
|
|
|
|
if ( static_cast<string>(xmlrpc_c::value_string(v)).size() > st_limit )
|
|
{
|
|
oss << "...";
|
|
}
|
|
|
|
oss << "\"";
|
|
break;
|
|
case xmlrpc_c::value::TYPE_DOUBLE:
|
|
oss << ", "
|
|
<< static_cast<double>(xmlrpc_c::value_double(v));
|
|
break;
|
|
default:
|
|
oss << ", unknown param type";
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool Request::basic_authorization(int oid,
|
|
AuthRequest::Operation op,
|
|
RequestAttributes& att)
|
|
{
|
|
PoolObjectSQL * object;
|
|
PoolObjectAuth perms;
|
|
|
|
if ( oid >= 0 )
|
|
{
|
|
object = pool->get(oid,true);
|
|
|
|
if ( object == 0 )
|
|
{
|
|
failure_response(NO_EXISTS,
|
|
get_error(object_name(auth_object),oid),
|
|
att);
|
|
return false;
|
|
}
|
|
|
|
if ( att.uid == 0 )
|
|
{
|
|
object->unlock();
|
|
return true;
|
|
}
|
|
|
|
object->get_permissions(perms);
|
|
|
|
object->unlock();
|
|
}
|
|
else
|
|
{
|
|
if ( att.uid == 0 )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
perms.obj_type = auth_object;
|
|
}
|
|
|
|
AuthRequest ar(att.uid, att.group_ids);
|
|
|
|
ar.add_auth(op, perms);
|
|
|
|
if (UserPool::authorize(ar) == -1)
|
|
{
|
|
failure_response(AUTHORIZATION,
|
|
authorization_error(ar.message, att),
|
|
att);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool Request::user_quota_authorization (Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att,
|
|
string& error_str)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
UserPool * upool = nd.get_upool();
|
|
User * user;
|
|
|
|
bool rc = false;
|
|
|
|
user = upool->get(att.uid, true);
|
|
|
|
if ( user == 0 )
|
|
{
|
|
error_str = "User not found";
|
|
return false;
|
|
}
|
|
|
|
DefaultQuotas default_user_quotas = nd.get_default_user_quota();
|
|
|
|
rc = user->quota.quota_check(qtype, tmpl, default_user_quotas, error_str);
|
|
|
|
if (rc == true)
|
|
{
|
|
upool->update_quotas(user);
|
|
}
|
|
else
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::USER) << " [" << att.uid << "] "
|
|
<< error_str;
|
|
|
|
error_str = oss.str();
|
|
}
|
|
|
|
user->unlock();
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool Request::group_quota_authorization (Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att,
|
|
string& error_str)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
GroupPool * gpool = nd.get_gpool();
|
|
Group * group;
|
|
|
|
bool rc = false;
|
|
|
|
group = gpool->get(att.gid, true);
|
|
|
|
if ( group == 0 )
|
|
{
|
|
error_str = "Group not found";
|
|
return false;
|
|
}
|
|
|
|
DefaultQuotas default_group_quotas = nd.get_default_group_quota();
|
|
|
|
rc = group->quota.quota_check(qtype, tmpl, default_group_quotas, error_str);
|
|
|
|
if (rc == true)
|
|
{
|
|
gpool->update_quotas(group);
|
|
}
|
|
else
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << object_name(PoolObjectSQL::GROUP) << " [" << att.gid << "] "
|
|
<< error_str;
|
|
|
|
error_str = oss.str();
|
|
}
|
|
|
|
group->unlock();
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::user_quota_rollback(Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
UserPool * upool = nd.get_upool();
|
|
|
|
User * user;
|
|
|
|
user = upool->get(att.uid, true);
|
|
|
|
if ( user == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
user->quota.quota_del(qtype, tmpl);
|
|
|
|
upool->update_quotas(user);
|
|
|
|
user->unlock();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::group_quota_rollback(Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att)
|
|
{
|
|
Nebula& nd = Nebula::instance();
|
|
GroupPool * gpool = nd.get_gpool();
|
|
|
|
Group * group;
|
|
|
|
group = gpool->get(att.gid, true);
|
|
|
|
if ( group == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
group->quota.quota_del(qtype, tmpl);
|
|
|
|
gpool->update_quotas(group);
|
|
|
|
group->unlock();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool Request::quota_authorization(Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att)
|
|
{
|
|
string error_str;
|
|
|
|
bool auth = quota_authorization(tmpl, qtype, att, error_str);
|
|
|
|
if ( auth == false )
|
|
{
|
|
failure_response(AUTHORIZATION,
|
|
request_error(error_str, ""),
|
|
att);
|
|
}
|
|
|
|
return auth;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
bool Request::quota_authorization(
|
|
Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att,
|
|
string& error_str)
|
|
{
|
|
// uid/gid == -1 means do not update user/group
|
|
|
|
bool do_user_quota = att.uid != UserPool::ONEADMIN_ID && att.uid != -1;
|
|
bool do_group_quota = att.gid != GroupPool::ONEADMIN_ID && att.gid != -1;
|
|
|
|
if ( do_user_quota )
|
|
{
|
|
if ( user_quota_authorization(tmpl, qtype, att, error_str) == false )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ( do_group_quota )
|
|
{
|
|
if ( group_quota_authorization(tmpl, qtype, att, error_str) == false )
|
|
{
|
|
if ( do_user_quota )
|
|
{
|
|
user_quota_rollback(tmpl, qtype, att);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::quota_rollback(Template * tmpl,
|
|
Quotas::QuotaType qtype,
|
|
RequestAttributes& att)
|
|
{
|
|
// uid/gid == -1 means do not update user/group
|
|
|
|
if ( att.uid != UserPool::ONEADMIN_ID && att.uid != -1 )
|
|
{
|
|
user_quota_rollback(tmpl, qtype, att);
|
|
}
|
|
|
|
if ( att.gid != GroupPool::ONEADMIN_ID && att.gid != -1 )
|
|
{
|
|
group_quota_rollback(tmpl, qtype, att);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::failure_response(ErrorCode ec, const string& str_val,
|
|
RequestAttributes& att)
|
|
{
|
|
vector<xmlrpc_c::value> arrayData;
|
|
|
|
arrayData.push_back(xmlrpc_c::value_boolean(false));
|
|
arrayData.push_back(xmlrpc_c::value_string(str_val));
|
|
arrayData.push_back(xmlrpc_c::value_int(ec));
|
|
|
|
xmlrpc_c::value_array arrayresult(arrayData);
|
|
|
|
*(att.retval) = arrayresult;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::success_response(int id, RequestAttributes& att)
|
|
{
|
|
vector<xmlrpc_c::value> arrayData;
|
|
|
|
arrayData.push_back(xmlrpc_c::value_boolean(true));
|
|
arrayData.push_back(xmlrpc_c::value_int(id));
|
|
arrayData.push_back(xmlrpc_c::value_int(SUCCESS));
|
|
|
|
|
|
xmlrpc_c::value_array arrayresult(arrayData);
|
|
|
|
*(att.retval) = arrayresult;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
void Request::success_response(const string& val, RequestAttributes& att)
|
|
{
|
|
vector<xmlrpc_c::value> arrayData;
|
|
|
|
arrayData.push_back(xmlrpc_c::value_boolean(true));
|
|
arrayData.push_back(xmlrpc_c::value_string(val));
|
|
arrayData.push_back(xmlrpc_c::value_int(SUCCESS));
|
|
|
|
xmlrpc_c::value_array arrayresult(arrayData);
|
|
|
|
*(att.retval) = arrayresult;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::object_name(PoolObjectSQL::ObjectType ob)
|
|
{
|
|
switch (ob)
|
|
{
|
|
case PoolObjectSQL::VM:
|
|
return "virtual machine";
|
|
case PoolObjectSQL::HOST:
|
|
return "host";
|
|
case PoolObjectSQL::NET:
|
|
return "virtual network";
|
|
case PoolObjectSQL::IMAGE:
|
|
return "image";
|
|
case PoolObjectSQL::USER:
|
|
return "user";
|
|
case PoolObjectSQL::TEMPLATE:
|
|
return "virtual machine template";
|
|
case PoolObjectSQL::GROUP:
|
|
return "group";
|
|
case PoolObjectSQL::ACL:
|
|
return "ACL";
|
|
case PoolObjectSQL::DATASTORE:
|
|
return "datastore";
|
|
case PoolObjectSQL::CLUSTER:
|
|
return "cluster";
|
|
case PoolObjectSQL::DOCUMENT:
|
|
return "document";
|
|
case PoolObjectSQL::ZONE:
|
|
return "zone";
|
|
default:
|
|
return "-";
|
|
}
|
|
};
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::authorization_error (const string &message,
|
|
RequestAttributes& att)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "[" << method_name << "]" << " User [" << att.uid << "] ";
|
|
|
|
if ( message.empty() )
|
|
{
|
|
oss << "not authorized to perform action on "
|
|
<< object_name(auth_object) << ".";
|
|
}
|
|
else
|
|
{
|
|
oss << ": " << message << ".";
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::authenticate_error()
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "[" << method_name << "]" << " User couldn't be authenticated," <<
|
|
" aborting call.";
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::get_error (const string &object,
|
|
int id)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "[" << method_name << "]" << " Error getting " <<
|
|
object;
|
|
|
|
if ( id != -1 )
|
|
{
|
|
oss << " [" << id << "].";
|
|
}
|
|
else
|
|
{
|
|
oss << " Pool.";
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::request_error (const string &err_desc, const string &err_detail)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "[" << method_name << "] " << err_desc;
|
|
|
|
if (!err_detail.empty())
|
|
{
|
|
oss << ". " << err_detail;
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::allocate_error(PoolObjectSQL::ObjectType obj,
|
|
const string& error)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "[" << method_name << "]" << " Error allocating a new "
|
|
<< object_name(obj) << ".";
|
|
|
|
if (!error.empty())
|
|
{
|
|
oss << " " << error;
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
string Request::allocate_error (const string& error)
|
|
{
|
|
ostringstream oss;
|
|
|
|
oss << "[" << method_name << "]" << " Error allocating a new "
|
|
<< object_name(auth_object) << ".";
|
|
|
|
if (!error.empty())
|
|
{
|
|
oss << " " << error;
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
int Request::get_info(
|
|
PoolSQL * pool,
|
|
int id,
|
|
PoolObjectSQL::ObjectType type,
|
|
RequestAttributes& att,
|
|
PoolObjectAuth& perms,
|
|
string& name,
|
|
bool throw_error)
|
|
{
|
|
PoolObjectSQL * ob;
|
|
|
|
if ((ob = pool->get(id,true)) == 0 )
|
|
{
|
|
if (throw_error)
|
|
{
|
|
failure_response(NO_EXISTS, get_error(object_name(type), id), att);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
ob->get_permissions(perms);
|
|
|
|
name = ob->get_name();
|
|
|
|
ob->unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* -------------------------------------------------------------------------- */
|