viridentity.c 17.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * viridentity.c: helper APIs for managing user identities
 *
 * Copyright (C) 2012-2013 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library;  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 */

#include <config.h>

24
#include <unistd.h>
25
#if WITH_SELINUX
26 27 28
# include <selinux/selinux.h>
#endif

29 30 31 32 33 34 35
#include "internal.h"
#include "viralloc.h"
#include "virerror.h"
#include "viridentity.h"
#include "virlog.h"
#include "virobject.h"
#include "virthread.h"
36
#include "virutil.h"
37
#include "virstring.h"
38
#include "virprocess.h"
39
#include "virtypedparam.h"
40 41 42

#define VIR_FROM_THIS VIR_FROM_IDENTITY

43
VIR_LOG_INIT("util.identity");
44 45 46 47

struct _virIdentity {
    virObject parent;

48 49 50
    int nparams;
    int maxparams;
    virTypedParameterPtr params;
51 52 53
};

static virClassPtr virIdentityClass;
54
static virThreadLocal virIdentityCurrent;
55 56 57 58 59

static void virIdentityDispose(void *obj);

static int virIdentityOnceInit(void)
{
60
    if (!VIR_CLASS_NEW(virIdentity, virClassForObject()))
61 62
        return -1;

63 64 65 66 67 68 69
    if (virThreadLocalInit(&virIdentityCurrent,
                           (virThreadLocalCleanup)virObjectUnref) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Cannot initialize thread local for current identity"));
        return -1;
    }

70 71 72
    return 0;
}

73
VIR_ONCE_GLOBAL_INIT(virIdentity);
74

75 76 77 78 79 80 81 82 83 84 85 86 87 88
/**
 * virIdentityGetCurrent:
 *
 * Get the current identity associated with this thread. The
 * caller will own a reference to the returned identity, but
 * must not modify the object in any way, other than to
 * release the reference when done with virObjectUnref
 *
 * Returns: a reference to the current identity, or NULL
 */
virIdentityPtr virIdentityGetCurrent(void)
{
    virIdentityPtr ident;

89
    if (virIdentityInitialize() < 0)
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
        return NULL;

    ident = virThreadLocalGet(&virIdentityCurrent);
    return virObjectRef(ident);
}


/**
 * virIdentitySetCurrent:
 *
 * Set the new identity to be associated with this thread.
 * The caller should not modify the passed identity after
 * it has been set, other than to release its own reference.
 *
 * Returns 0 on success, or -1 on error
 */
int virIdentitySetCurrent(virIdentityPtr ident)
{
    virIdentityPtr old;

110
    if (virIdentityInitialize() < 0)
111 112 113 114 115 116 117 118
        return -1;

    old = virThreadLocalGet(&virIdentityCurrent);

    if (virThreadLocalSet(&virIdentityCurrent,
                          virObjectRef(ident)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unable to set thread local identity"));
119
        virObjectUnref(ident);
120 121 122
        return -1;
    }

123 124
    virObjectUnref(old);

125 126 127
    return 0;
}

128

129 130 131 132 133 134 135 136 137 138
/**
 * virIdentityGetSystem:
 *
 * Returns an identity that represents the system itself.
 * This is the identity that the process is running as
 *
 * Returns a reference to the system identity, or NULL
 */
virIdentityPtr virIdentityGetSystem(void)
{
139 140
    VIR_AUTOFREE(char *) username = NULL;
    VIR_AUTOFREE(char *) groupname = NULL;
141
    unsigned long long startTime;
142
    virIdentityPtr ret = NULL;
143
#if WITH_SELINUX
144 145
    security_context_t con;
#endif
146

147 148
    if (!(ret = virIdentityNew()))
        goto error;
149

150
    if (virIdentitySetProcessID(ret, getpid()) < 0)
151
        goto error;
152

153 154 155
    if (virProcessGetStartTime(getpid(), &startTime) < 0)
        goto error;
    if (startTime != 0 &&
156
        virIdentitySetProcessTime(ret, startTime) < 0)
157
        goto error;
158

159
    if (!(username = virGetUserName(geteuid())))
160
        return ret;
161
    if (virIdentitySetUserName(ret, username) < 0)
162 163 164
        goto error;
    if (virIdentitySetUNIXUserID(ret, getuid()) < 0)
        goto error;
165

166
    if (!(groupname = virGetGroupName(getegid())))
167
        return ret;
168
    if (virIdentitySetGroupName(ret, groupname) < 0)
169 170 171
        goto error;
    if (virIdentitySetUNIXGroupID(ret, getgid()) < 0)
        goto error;
172

173
#if WITH_SELINUX
174
    if (is_selinux_enabled() > 0) {
175 176 177
        if (getcon(&con) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Unable to lookup SELinux process context"));
178
            return ret;
179
        }
180
        if (virIdentitySetSELinuxContext(ret, con) < 0) {
181
            freecon(con);
182
            goto error;
183
        }
184
        freecon(con);
185 186 187 188 189
    }
#endif

    return ret;

190
 error:
191
    virObjectUnref(ret);
192
    return NULL;
193 194 195
}


196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
/**
 * virIdentityNew:
 *
 * Creates a new empty identity object. After creating, one or
 * more identifying attributes should be set on the identity.
 *
 * Returns: a new empty identity
 */
virIdentityPtr virIdentityNew(void)
{
    virIdentityPtr ident;

    if (virIdentityInitialize() < 0)
        return NULL;

    if (!(ident = virObjectNew(virIdentityClass)))
        return NULL;

    return ident;
}


static void virIdentityDispose(void *object)
{
    virIdentityPtr ident = object;

222
    virTypedParamsFree(ident->params, ident->nparams);
223 224 225
}


226 227 228
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
229 230
int virIdentityGetUserName(virIdentityPtr ident,
                           const char **username)
231
{
232 233 234 235 236
    *username = NULL;
    return virTypedParamsGetString(ident->params,
                                   ident->nparams,
                                   VIR_CONNECT_IDENTITY_USER_NAME,
                                   username);
237 238 239
}


240 241 242
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
243 244 245
int virIdentityGetUNIXUserID(virIdentityPtr ident,
                             uid_t *uid)
{
246 247
    unsigned long long val;
    int rc;
248 249

    *uid = -1;
250 251 252 253 254 255
    rc = virTypedParamsGetULLong(ident->params,
                                 ident->nparams,
                                 VIR_CONNECT_IDENTITY_UNIX_USER_ID,
                                 &val);
    if (rc <= 0)
        return rc;
256 257 258

    *uid = (uid_t)val;

259
    return 1;
260 261
}

262 263 264 265

/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
266 267
int virIdentityGetGroupName(virIdentityPtr ident,
                            const char **groupname)
268
{
269 270 271 272 273
    *groupname = NULL;
    return virTypedParamsGetString(ident->params,
                                   ident->nparams,
                                   VIR_CONNECT_IDENTITY_GROUP_NAME,
                                   groupname);
274 275 276
}


277 278 279
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
280 281 282
int virIdentityGetUNIXGroupID(virIdentityPtr ident,
                              gid_t *gid)
{
283 284
    unsigned long long val;
    int rc;
285 286

    *gid = -1;
287 288 289 290 291 292
    rc = virTypedParamsGetULLong(ident->params,
                                 ident->nparams,
                                 VIR_CONNECT_IDENTITY_UNIX_GROUP_ID,
                                 &val);
    if (rc <= 0)
        return rc;
293 294 295

    *gid = (gid_t)val;

296
    return 1;
297 298 299
}


300 301 302
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
303 304
int virIdentityGetProcessID(virIdentityPtr ident,
                            pid_t *pid)
305
{
306 307
    long long val;
    int rc;
308 309

    *pid = 0;
310 311 312 313 314 315
    rc = virTypedParamsGetLLong(ident->params,
                                ident->nparams,
                                VIR_CONNECT_IDENTITY_PROCESS_ID,
                                &val);
    if (rc <= 0)
        return rc;
316 317 318

    *pid = (pid_t)val;

319
    return 1;
320 321 322
}


323 324 325
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
326 327
int virIdentityGetProcessTime(virIdentityPtr ident,
                              unsigned long long *timestamp)
328
{
329
    *timestamp = 0;
330 331 332 333
    return virTypedParamsGetULLong(ident->params,
                                   ident->nparams,
                                   VIR_CONNECT_IDENTITY_PROCESS_TIME,
                                   timestamp);
334 335 336
}


337 338 339
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
340 341 342
int virIdentityGetSASLUserName(virIdentityPtr ident,
                               const char **username)
{
343 344 345 346 347
    *username = NULL;
    return virTypedParamsGetString(ident->params,
                                   ident->nparams,
                                   VIR_CONNECT_IDENTITY_SASL_USER_NAME,
                                   username);
348 349 350
}


351 352 353
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
354 355 356
int virIdentityGetX509DName(virIdentityPtr ident,
                            const char **dname)
{
357 358 359 360 361
    *dname = NULL;
    return virTypedParamsGetString(ident->params,
                                   ident->nparams,
                                   VIR_CONNECT_IDENTITY_X509_DISTINGUISHED_NAME,
                                   dname);
362 363 364
}


365 366 367
/*
 * Returns: 0 if not present, 1 if present, -1 on error
 */
368 369 370
int virIdentityGetSELinuxContext(virIdentityPtr ident,
                                 const char **context)
{
371 372 373 374 375
    *context = NULL;
    return virTypedParamsGetString(ident->params,
                                   ident->nparams,
                                   VIR_CONNECT_IDENTITY_SELINUX_CONTEXT,
                                   context);
376 377 378
}


379 380
int virIdentitySetUserName(virIdentityPtr ident,
                           const char *username)
381
{
382 383 384 385 386 387 388 389 390 391 392 393 394
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_USER_NAME)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
        return -1;
    }

    return virTypedParamsAddString(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_USER_NAME,
                                   username);
395 396 397 398 399 400
}


int virIdentitySetUNIXUserID(virIdentityPtr ident,
                             uid_t uid)
{
401 402 403 404 405
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_UNIX_USER_ID)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
406
        return -1;
407
    }
408

409 410 411 412 413
    return virTypedParamsAddULLong(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_UNIX_USER_ID,
                                   uid);
414 415 416
}


417 418
int virIdentitySetGroupName(virIdentityPtr ident,
                            const char *groupname)
419
{
420 421 422 423 424 425 426 427 428 429 430 431 432
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_GROUP_NAME)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
        return -1;
    }

    return virTypedParamsAddString(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_GROUP_NAME,
                                   groupname);
433 434 435 436 437 438
}


int virIdentitySetUNIXGroupID(virIdentityPtr ident,
                              gid_t gid)
{
439 440 441 442 443
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_UNIX_GROUP_ID)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
444
        return -1;
445
    }
446

447 448 449 450 451
    return virTypedParamsAddULLong(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_UNIX_GROUP_ID,
                                   gid);
452 453 454
}


455 456
int virIdentitySetProcessID(virIdentityPtr ident,
                            pid_t pid)
457
{
458 459 460 461 462
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_PROCESS_ID)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
463
        return -1;
464
    }
465

466 467 468 469 470
    return virTypedParamsAddLLong(&ident->params,
                                  &ident->nparams,
                                  &ident->maxparams,
                                  VIR_CONNECT_IDENTITY_PROCESS_ID,
                                  pid);
471 472 473
}


474 475
int virIdentitySetProcessTime(virIdentityPtr ident,
                              unsigned long long timestamp)
476
{
477 478 479 480 481
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_PROCESS_TIME)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
482
        return -1;
483
    }
484

485 486 487 488 489
    return virTypedParamsAddULLong(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_PROCESS_TIME,
                                   timestamp);
490 491 492 493 494 495 496
}



int virIdentitySetSASLUserName(virIdentityPtr ident,
                               const char *username)
{
497 498 499 500 501 502 503 504 505 506 507 508 509
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_SASL_USER_NAME)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
        return -1;
    }

    return virTypedParamsAddString(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_SASL_USER_NAME,
                                   username);
510 511 512 513 514 515
}


int virIdentitySetX509DName(virIdentityPtr ident,
                            const char *dname)
{
516 517 518 519 520 521 522 523 524 525 526 527 528
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_X509_DISTINGUISHED_NAME)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
        return -1;
    }

    return virTypedParamsAddString(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_X509_DISTINGUISHED_NAME,
                                   dname);
529 530 531 532 533 534
}


int virIdentitySetSELinuxContext(virIdentityPtr ident,
                                 const char *context)
{
535 536 537 538 539 540 541 542 543 544 545 546 547
    if (virTypedParamsGet(ident->params,
                          ident->nparams,
                          VIR_CONNECT_IDENTITY_SELINUX_CONTEXT)) {
        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
                       _("Identity attribute is already set"));
        return -1;
    }

    return virTypedParamsAddString(&ident->params,
                                   &ident->nparams,
                                   &ident->maxparams,
                                   VIR_CONNECT_IDENTITY_SELINUX_CONTEXT,
                                   context);
548
}
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603


int virIdentitySetParameters(virIdentityPtr ident,
                             virTypedParameterPtr params,
                             int nparams)
{
    if (virTypedParamsValidate(params, nparams,
                               VIR_CONNECT_IDENTITY_USER_NAME,
                               VIR_TYPED_PARAM_STRING,
                               VIR_CONNECT_IDENTITY_UNIX_USER_ID,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_CONNECT_IDENTITY_GROUP_NAME,
                               VIR_TYPED_PARAM_STRING,
                               VIR_CONNECT_IDENTITY_UNIX_GROUP_ID,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_CONNECT_IDENTITY_PROCESS_ID,
                               VIR_TYPED_PARAM_LLONG,
                               VIR_CONNECT_IDENTITY_PROCESS_TIME,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_CONNECT_IDENTITY_SASL_USER_NAME,
                               VIR_TYPED_PARAM_STRING,
                               VIR_CONNECT_IDENTITY_X509_DISTINGUISHED_NAME,
                               VIR_TYPED_PARAM_STRING,
                               VIR_CONNECT_IDENTITY_SELINUX_CONTEXT,
                               VIR_TYPED_PARAM_STRING,
                               NULL) < 0)
        return -1;

    virTypedParamsFree(ident->params, ident->nparams);
    ident->params = NULL;
    ident->nparams = 0;
    ident->maxparams = 0;
    if (virTypedParamsCopy(&ident->params, params, nparams) < 0)
        return -1;
    ident->nparams = nparams;
    ident->maxparams = nparams;

    return 0;
}


int virIdentityGetParameters(virIdentityPtr ident,
                             virTypedParameterPtr *params,
                             int *nparams)
{
    *params = NULL;
    *nparams = 0;

    if (virTypedParamsCopy(params, ident->params, ident->nparams) < 0)
        return -1;

    *nparams = ident->nparams;

    return 0;
}