Statistics
| Branch: | Tag: | Revision:

one / src / rm / Request.cc @ 202b47e9

History | View | Annotate | Download (21 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems                */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

    
17
#include "Request.h"
18
#include "Nebula.h"
19

    
20
#include "PoolObjectAuth.h"
21

    
22
/* -------------------------------------------------------------------------- */
23
/* -------------------------------------------------------------------------- */
24
/* RequestLog Methods                                                         */
25
/* -------------------------------------------------------------------------- */
26
/* -------------------------------------------------------------------------- */
27

    
28
string Request::object_name(PoolObjectSQL::ObjectType ob)
29
{
30
    switch (ob)
31
    {
32
        case PoolObjectSQL::VM:
33
            return "virtual machine";
34
        case PoolObjectSQL::HOST:
35
            return "host";
36
        case PoolObjectSQL::NET:
37
            return "virtual network";
38
        case PoolObjectSQL::IMAGE:
39
            return "image";
40
        case PoolObjectSQL::USER:
41
            return "user";
42
        case PoolObjectSQL::TEMPLATE:
43
            return "virtual machine template";
44
        case PoolObjectSQL::GROUP:
45
            return "group";
46
        case PoolObjectSQL::ACL:
47
            return "ACL";
48
        case PoolObjectSQL::DATASTORE:
49
            return "datastore";
50
        case PoolObjectSQL::CLUSTER:
51
            return "cluster";
52
        case PoolObjectSQL::DOCUMENT:
53
            return "document";
54
        case PoolObjectSQL::ZONE:
55
            return "zone";
56
        case PoolObjectSQL::SECGROUP:
57
            return "security group";
58
        case PoolObjectSQL::VDC:
59
            return "VDC";
60
        case PoolObjectSQL::VROUTER:
61
            return "virtual router";
62
        case PoolObjectSQL::MARKETPLACE:
63
            return "marketplace";
64
        case PoolObjectSQL::MARKETPLACEAPP:
65
            return "marketplaceapp";
66
        case PoolObjectSQL::VMGROUP:
67
            return "vm group";
68
        default:
69
            return "-";
70
      }
71
};
72

    
73
/* -------------------------------------------------------------------------- */
74
/* -------------------------------------------------------------------------- */
75

    
76
void Request::log_method_invoked(const RequestAttributes& att,
77
        const xmlrpc_c::paramList&  paramList, const string& format_str,
78
        const std::string& method_name, const std::set<int>& hidden_params)
79
{
80
    std::ostringstream oss;
81

    
82
    for (unsigned int j = 0 ;j < format_str.length() - 1; j++ )
83
    {
84
        if (format_str[j] != '%')
85
        {
86
            oss << format_str[j];
87
        }
88
        else
89
        {
90
            char mod = format_str[j+1];
91

    
92
            switch(mod)
93
            {
94
                case '%':
95
                    oss << "%";
96
                break;
97

    
98
                case 'i':
99
                    oss << att.req_id;
100
                break;
101

    
102
                case 'u':
103
                    oss << att.uid;
104
                break;
105

    
106
                case 'U':
107
                    oss << att.uname;
108
                break;
109

    
110
                case 'g':
111
                    oss << att.gid;
112
                break;
113

    
114
                case 'G':
115
                    oss << att.gname;
116
                break;
117

    
118
                case 'p':
119
                    oss << att.password;
120
                break;
121

    
122
                case 'a':
123
                    oss << att.session;
124
                break;
125

    
126
                case 'm':
127
                    oss << method_name;
128
                break;
129

    
130
                case 'l':
131
                    for (unsigned int i=1; i<paramList.size(); i++)
132
                    {
133
                        if ( hidden_params.count(i) == 1 )
134
                        {
135
                            oss << ", ****";
136
                        }
137
                        else
138
                        {
139
                            log_xmlrpc_value(paramList[i], oss);
140
                        }
141
                    }
142
                break;
143

    
144
                default:
145
                    oss << format_str[j] << format_str[j+1];
146
                break;
147
            }
148

    
149
            j = j+1;
150
        }
151
    }
152

    
153
    NebulaLog::log("ReM", Log::DEBUG, oss);
154
}
155

    
156
/* -------------------------------------------------------------------------- */
157
/* -------------------------------------------------------------------------- */
158

    
159
void Request::log_result(const RequestAttributes& att, const string& method_name)
160
{
161
    std::ostringstream oss;
162

    
163
    oss << "Req:" << att.req_id << " UID:";
164

    
165
    if ( att.uid != -1 )
166
    {
167
        oss << att.uid;
168
    }
169
    else
170
    {
171
        oss << "-";
172
    }
173

    
174
    oss << " " << method_name << " result ";
175

    
176
    xmlrpc_c::value_array array1(*att.retval);
177
    vector<xmlrpc_c::value> const vvalue(array1.vectorValueValue());
178

    
179
    if ( static_cast<bool>(xmlrpc_c::value_boolean(vvalue[0])) )
180
    {
181
        oss << "SUCCESS";
182

    
183
        for (unsigned int i=1; i<vvalue.size()-1; i++)
184
        {
185
            log_xmlrpc_value(vvalue[i], oss);
186
        }
187

    
188
        NebulaLog::log("ReM", Log::DEBUG, oss);
189
    }
190
    else
191
    {
192
        oss << "FAILURE "
193
            << static_cast<string>(xmlrpc_c::value_string(vvalue[1]));
194

    
195
        NebulaLog::log("ReM", Log::ERROR, oss);
196
    }
197
}
198

    
199
/* -------------------------------------------------------------------------- */
200
/* -------------------------------------------------------------------------- */
201

    
202
void Request::log_xmlrpc_value(const xmlrpc_c::value& v, std::ostringstream& oss)
203
{
204
    size_t st_limit = 20;
205
    size_t st_newline;
206

    
207
    switch (v.type())
208
    {
209
        case xmlrpc_c::value::TYPE_INT:
210
            oss << ", " << static_cast<int>(xmlrpc_c::value_int(v));
211
            break;
212
        case xmlrpc_c::value::TYPE_BOOLEAN:
213
            oss << ", ";
214

    
215
            if ( static_cast<bool>(xmlrpc_c::value_boolean(v)) )
216
            {
217
                oss << "true";
218
            }
219
            else
220
            {
221
                oss << "false";
222
            }
223

    
224
            break;
225
        case xmlrpc_c::value::TYPE_STRING:
226
            st_newline =
227
                    static_cast<string>(xmlrpc_c::value_string(v)).find("\n");
228

    
229
            if ( st_newline < st_limit )
230
            {
231
                st_limit = st_newline;
232
            }
233

    
234
            oss << ", \"" <<
235
                static_cast<string>(xmlrpc_c::value_string(v)).substr(0,st_limit);
236

    
237
            if ( static_cast<string>(xmlrpc_c::value_string(v)).size() > st_limit )
238
            {
239
                oss << "...";
240
            }
241

    
242
            oss << "\"";
243
            break;
244
        case xmlrpc_c::value::TYPE_DOUBLE:
245
            oss << ", "
246
                << static_cast<double>(xmlrpc_c::value_double(v));
247
            break;
248
        default:
249
            oss  << ", unknown param type";
250
            break;
251
    }
252
}
253

    
254
/* -------------------------------------------------------------------------- */
255
/* -------------------------------------------------------------------------- */
256
/* Request Methods                                                            */
257
/* -------------------------------------------------------------------------- */
258
/* -------------------------------------------------------------------------- */
259

    
260
string Request::format_str;
261

    
262
/* -------------------------------------------------------------------------- */
263

    
264
void Request::execute(
265
        xmlrpc_c::paramList const& _paramList,
266
        xmlrpc_c::value *   const  _retval)
267
{
268
    RequestAttributes att;
269

    
270
    att.retval  = _retval;
271
    att.session = xmlrpc_c::value_string (_paramList.getString(0));
272

    
273
    att.req_id = (reinterpret_cast<uintptr_t>(this) * rand()) % 10000;
274

    
275
    Nebula& nd = Nebula::instance();
276
    UserPool* upool = nd.get_upool();
277

    
278
    bool authenticated = upool->authenticate(att.session,
279
                                             att.password,
280
                                             att.uid,
281
                                             att.gid,
282
                                             att.uname,
283
                                             att.gname,
284
                                             att.group_ids,
285
                                             att.umask);
286

    
287
    log_method_invoked(att, _paramList, format_str, method_name, hidden_params);
288

    
289
    if ( authenticated == false )
290
    {
291
        failure_response(AUTHENTICATION, att);
292
    }
293
    else
294
    {
295
        request_execute(_paramList, att);
296
    }
297

    
298
    log_result(att, method_name);
299
};
300

    
301
/* -------------------------------------------------------------------------- */
302
/* -------------------------------------------------------------------------- */
303

    
304
bool Request::basic_authorization(int oid,
305
                                  AuthRequest::Operation op,
306
                                  RequestAttributes& att)
307
{
308
    ErrorCode ec = basic_authorization(pool, oid, op, auth_object, att);
309

    
310
    if (ec == SUCCESS)
311
    {
312
        return true;
313
    }
314
    else
315
    {
316
        failure_response(ec, att);
317
        return false;
318
    }
319
}
320

    
321
/* -------------------------------------------------------------------------- */
322
/* -------------------------------------------------------------------------- */
323

    
324
Request::ErrorCode Request::basic_authorization(
325
        PoolSQL*                pool,
326
        int                     oid,
327
        AuthRequest::Operation  op,
328
        PoolObjectSQL::ObjectType auth_object,
329
        RequestAttributes&      att)
330
{
331
    PoolObjectSQL * object;
332
    PoolObjectAuth  perms;
333

    
334
    if ( oid >= 0 )
335
    {
336
        object = pool->get(oid,true);
337

    
338
        if ( object == 0 )
339
        {
340
            att.resp_id = oid;
341

    
342
            return NO_EXISTS;
343
        }
344

    
345
        if ( att.uid == 0 )
346
        {
347
            object->unlock();
348
            return SUCCESS;
349
        }
350

    
351
        object->get_permissions(perms);
352

    
353
        object->unlock();
354
    }
355
    else
356
    {
357
        if ( att.uid == 0 )
358
        {
359
            return SUCCESS;
360
        }
361

    
362
        perms.obj_type = auth_object;
363
    }
364

    
365
    AuthRequest ar(att.uid, att.group_ids);
366

    
367
    ar.add_auth(op, perms);
368

    
369
    if (UserPool::authorize(ar) == -1)
370
    {
371
        att.resp_msg = ar.message;
372

    
373
        return AUTHORIZATION;
374
    }
375

    
376
    return SUCCESS;
377
}
378

    
379
/* -------------------------------------------------------------------------- */
380
/* -------------------------------------------------------------------------- */
381

    
382
bool Request::user_quota_authorization (Template * tmpl,
383
                                        Quotas::QuotaType  qtype,
384
                                        RequestAttributes& att,
385
                                        string& error_str)
386
{
387
    Nebula& nd        = Nebula::instance();
388
    UserPool *  upool = nd.get_upool();
389
    User *      user;
390

    
391
    bool   rc = false;
392

    
393
    user = upool->get(att.uid, true);
394

    
395
    if ( user == 0 )
396
    {
397
        error_str = "User not found";
398
        return false;
399
    }
400

    
401
    DefaultQuotas default_user_quotas = nd.get_default_user_quota();
402

    
403
    rc = user->quota.quota_check(qtype, tmpl, default_user_quotas, error_str);
404

    
405
    if (rc == true)
406
    {
407
        upool->update_quotas(user);
408
    }
409
    else
410
    {
411
        ostringstream oss;
412

    
413
        oss << object_name(PoolObjectSQL::USER) << " [" << att.uid << "] "
414
            << error_str;
415

    
416
        error_str = oss.str();
417
    }
418

    
419
    user->unlock();
420

    
421
    return rc;
422
}
423

    
424
/* -------------------------------------------------------------------------- */
425

    
426
bool Request::group_quota_authorization (Template * tmpl,
427
                                         Quotas::QuotaType  qtype,
428
                                         RequestAttributes& att,
429
                                         string& error_str)
430
{
431
    Nebula&     nd    = Nebula::instance();
432
    GroupPool * gpool = nd.get_gpool();
433
    Group *     group;
434

    
435
    bool   rc = false;
436

    
437
    group = gpool->get(att.gid, true);
438

    
439
    if ( group == 0 )
440
    {
441
        error_str = "Group not found";
442
        return false;
443
    }
444

    
445
    DefaultQuotas default_group_quotas = nd.get_default_group_quota();
446

    
447
    rc = group->quota.quota_check(qtype, tmpl, default_group_quotas, error_str);
448

    
449
    if (rc == true)
450
    {
451
        gpool->update_quotas(group);
452
    }
453
    else
454
    {
455
        ostringstream oss;
456

    
457
        oss << object_name(PoolObjectSQL::GROUP) << " [" << att.gid << "] "
458
            << error_str;
459

    
460
        error_str = oss.str();
461
    }
462

    
463
    group->unlock();
464

    
465
    return rc;
466
}
467

    
468
/* -------------------------------------------------------------------------- */
469

    
470
void Request::user_quota_rollback(Template *         tmpl,
471
                                  Quotas::QuotaType  qtype,
472
                                  RequestAttributes& att)
473
{
474
    Nebula& nd        = Nebula::instance();
475
    UserPool * upool  = nd.get_upool();
476

    
477
    User * user;
478

    
479
    user = upool->get(att.uid, true);
480

    
481
    if ( user == 0 )
482
    {
483
        return;
484
    }
485

    
486
    user->quota.quota_del(qtype, tmpl);
487

    
488
    upool->update_quotas(user);
489

    
490
    user->unlock();
491
}
492

    
493
/* -------------------------------------------------------------------------- */
494

    
495
void Request::group_quota_rollback(Template *         tmpl,
496
                                   Quotas::QuotaType  qtype,
497
                                   RequestAttributes& att)
498
{
499
    Nebula& nd        = Nebula::instance();
500
    GroupPool * gpool = nd.get_gpool();
501

    
502
    Group * group;
503

    
504
    group = gpool->get(att.gid, true);
505

    
506
    if ( group == 0 )
507
    {
508
        return;
509
    }
510

    
511
    group->quota.quota_del(qtype, tmpl);
512

    
513
    gpool->update_quotas(group);
514

    
515
    group->unlock();
516
}
517

    
518
/* -------------------------------------------------------------------------- */
519
/* -------------------------------------------------------------------------- */
520

    
521
bool Request::quota_authorization(Template *         tmpl,
522
                                  Quotas::QuotaType  qtype,
523
                                  RequestAttributes& att)
524
{
525
    bool auth = quota_authorization(tmpl, qtype, att, att.resp_msg);
526

    
527
    if ( auth == false )
528
    {
529
        failure_response(AUTHORIZATION, att);
530
    }
531

    
532
    return auth;
533
}
534

    
535
/* -------------------------------------------------------------------------- */
536
/* -------------------------------------------------------------------------- */
537

    
538
bool Request::quota_authorization(
539
        Template *          tmpl,
540
        Quotas::QuotaType   qtype,
541
        RequestAttributes&  att,
542
        string&             error_str)
543
{
544
    // uid/gid == -1 means do not update user/group
545

    
546
    bool do_user_quota = att.uid != UserPool::ONEADMIN_ID && att.uid != -1;
547
    bool do_group_quota = att.gid != GroupPool::ONEADMIN_ID && att.gid != -1;
548

    
549
    if ( do_user_quota )
550
    {
551
        if ( user_quota_authorization(tmpl, qtype, att, error_str) == false )
552
        {
553
            return false;
554
        }
555
    }
556

    
557
    if ( do_group_quota )
558
    {
559
        if ( group_quota_authorization(tmpl, qtype, att, error_str) == false )
560
        {
561
            if ( do_user_quota )
562
            {
563
                user_quota_rollback(tmpl, qtype, att);
564
            }
565

    
566
            return false;
567
        }
568
    }
569

    
570
    return true;
571
}
572

    
573
/* -------------------------------------------------------------------------- */
574
/* -------------------------------------------------------------------------- */
575

    
576
void Request::quota_rollback(Template *         tmpl,
577
                             Quotas::QuotaType  qtype,
578
                             RequestAttributes& att)
579
{
580
    // uid/gid == -1 means do not update user/group
581

    
582
    if ( att.uid != UserPool::ONEADMIN_ID && att.uid != -1 )
583
    {
584
        user_quota_rollback(tmpl, qtype, att);
585
    }
586

    
587
    if ( att.gid != GroupPool::ONEADMIN_ID && att.gid != -1 )
588
    {
589
        group_quota_rollback(tmpl, qtype, att);
590
    }
591
}
592

    
593
/* -------------------------------------------------------------------------- */
594
/* -------------------------------------------------------------------------- */
595

    
596
void Request::failure_response(ErrorCode ec, const string& str_val,
597
                               RequestAttributes& att)
598
{
599
    vector<xmlrpc_c::value> arrayData;
600

    
601
    arrayData.push_back(xmlrpc_c::value_boolean(false));
602
    arrayData.push_back(xmlrpc_c::value_string(str_val));
603
    arrayData.push_back(xmlrpc_c::value_int(ec));
604

    
605
    xmlrpc_c::value_array arrayresult(arrayData);
606

    
607
    *(att.retval) = arrayresult;
608
}
609

    
610
/* -------------------------------------------------------------------------- */
611

    
612
string Request::failure_message(ErrorCode ec, RequestAttributes& att)
613
{
614
    std::ostringstream oss;
615
    std::string        obname;
616

    
617
    if ( att.resp_obj == PoolObjectSQL::NONE )
618
    {
619
        obname = object_name(auth_object);
620
    }
621
    else
622
    {
623
        obname = object_name(att.resp_obj);
624
    }
625

    
626
    oss << "[" << method_name << "] ";
627

    
628
    switch(ec)
629
    {
630
        case SUCCESS:
631
            return "";
632

    
633
        case AUTHORIZATION:
634
            oss << "User [" << att.uid << "] ";
635

    
636
            if (att.resp_msg.empty())
637
            {
638
                oss << "not authorized to perform action on " << obname << ".";
639
            }
640
            else
641
            {
642
                oss << ": " << att.resp_msg << ".";
643
            }
644
            break;
645

    
646
        case AUTHENTICATION:
647
            oss << "User couldn't be authenticated, aborting call.";
648
            break;
649

    
650
        case ACTION:
651
        case XML_RPC_API:
652
        case INTERNAL:
653
            oss << att.resp_msg;
654
            break;
655

    
656
        case NO_EXISTS:
657
            oss << "Error getting " << obname;
658

    
659
            if ( att.resp_id != -1 )
660
            {
661
               oss << " [" << att.resp_id << "].";
662
            }
663
            else
664
            {
665
              oss << " Pool.";
666
            }
667
            break;
668

    
669
        case ALLOCATE:
670
            oss << "Error allocating a new " << obname << ".";
671

    
672
            if (!att.resp_msg.empty())
673
            {
674
                oss << " " << att.resp_msg;
675
            }
676
            break;
677
    }
678

    
679
    return oss.str();
680
}
681

    
682
/* -------------------------------------------------------------------------- */
683
/* -------------------------------------------------------------------------- */
684

    
685
void Request::failure_response(ErrorCode ec, RequestAttributes& att)
686
{
687
    failure_response(ec, failure_message(ec, att), att);
688
}
689

    
690
/* -------------------------------------------------------------------------- */
691
/* -------------------------------------------------------------------------- */
692

    
693
void Request::success_response(int id, RequestAttributes& att)
694
{
695
    vector<xmlrpc_c::value> arrayData;
696

    
697
    arrayData.push_back(xmlrpc_c::value_boolean(true));
698
    arrayData.push_back(xmlrpc_c::value_int(id));
699
    arrayData.push_back(xmlrpc_c::value_int(SUCCESS));
700

    
701

    
702
    xmlrpc_c::value_array arrayresult(arrayData);
703

    
704
    *(att.retval) = arrayresult;
705
}
706

    
707
/* -------------------------------------------------------------------------- */
708

    
709
void Request::success_response(const string& val, RequestAttributes& att)
710
{
711
    vector<xmlrpc_c::value> arrayData;
712

    
713
    arrayData.push_back(xmlrpc_c::value_boolean(true));
714
    arrayData.push_back(xmlrpc_c::value_string(val));
715
    arrayData.push_back(xmlrpc_c::value_int(SUCCESS));
716

    
717
    xmlrpc_c::value_array arrayresult(arrayData);
718

    
719
    *(att.retval) = arrayresult;
720
}
721

    
722
/* -------------------------------------------------------------------------- */
723
/* -------------------------------------------------------------------------- */
724

    
725
void Request::success_response(bool val, RequestAttributes& att)
726
{
727
    vector<xmlrpc_c::value> arrayData;
728

    
729
    arrayData.push_back(xmlrpc_c::value_boolean(true));
730
    arrayData.push_back(xmlrpc_c::value_boolean(val));
731
    arrayData.push_back(xmlrpc_c::value_int(SUCCESS));
732

    
733

    
734
    xmlrpc_c::value_array arrayresult(arrayData);
735

    
736
    *(att.retval) = arrayresult;
737
}
738

    
739
/* -------------------------------------------------------------------------- */
740
/* -------------------------------------------------------------------------- */
741

    
742
int Request::get_info(
743
        PoolSQL *                 pool,
744
        int                       id,
745
        PoolObjectSQL::ObjectType type,
746
        RequestAttributes&        att,
747
        PoolObjectAuth&           perms,
748
        string&                   name,
749
        bool                      throw_error)
750
{
751
    PoolObjectSQL * ob;
752

    
753
    if ((ob = pool->get(id,true)) == 0 )
754
    {
755
        if (throw_error)
756
        {
757
            att.resp_obj = type;
758
            att.resp_id  = id;
759
            failure_response(NO_EXISTS, att);
760
        }
761

    
762
        return -1;
763
    }
764

    
765
    ob->get_permissions(perms);
766

    
767
    name = ob->get_name();
768

    
769
    ob->unlock();
770

    
771
    return 0;
772
}
773

    
774
/* -------------------------------------------------------------------------- */
775
/* -------------------------------------------------------------------------- */