1350 lines
43 KiB
C
1350 lines
43 KiB
C
/***
|
|
This file is part of systemd.
|
|
|
|
Copyright 2013 Lennart Poettering
|
|
|
|
systemd 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.
|
|
|
|
systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
***/
|
|
|
|
#include <linux/capability.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "alloc-util.h"
|
|
#include "audit-util.h"
|
|
#include "bus-creds.h"
|
|
#include "bus-label.h"
|
|
#include "bus-message.h"
|
|
#include "bus-util.h"
|
|
#include "capability-util.h"
|
|
#include "cgroup-util.h"
|
|
#include "fd-util.h"
|
|
#include "fileio.h"
|
|
#include "format-util.h"
|
|
#include "hexdecoct.h"
|
|
#include "parse-util.h"
|
|
#include "process-util.h"
|
|
#include "string-util.h"
|
|
#include "strv.h"
|
|
#include "terminal-util.h"
|
|
#include "user-util.h"
|
|
#include "util.h"
|
|
|
|
enum {
|
|
CAP_OFFSET_INHERITABLE = 0,
|
|
CAP_OFFSET_PERMITTED = 1,
|
|
CAP_OFFSET_EFFECTIVE = 2,
|
|
CAP_OFFSET_BOUNDING = 3
|
|
};
|
|
|
|
void bus_creds_done(sd_bus_creds *c) {
|
|
assert(c);
|
|
|
|
/* For internal bus cred structures that are allocated by
|
|
* something else */
|
|
|
|
free(c->session);
|
|
free(c->unit);
|
|
free(c->user_unit);
|
|
free(c->slice);
|
|
free(c->user_slice);
|
|
free(c->unescaped_description);
|
|
free(c->supplementary_gids);
|
|
free(c->tty);
|
|
|
|
free(c->well_known_names); /* note that this is an strv, but
|
|
* we only free the array, not the
|
|
* strings the array points to. The
|
|
* full strv we only free if
|
|
* c->allocated is set, see
|
|
* below. */
|
|
|
|
strv_free(c->cmdline_array);
|
|
}
|
|
|
|
_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
|
|
|
|
if (!c)
|
|
return NULL;
|
|
|
|
if (c->allocated) {
|
|
assert(c->n_ref > 0);
|
|
c->n_ref++;
|
|
} else {
|
|
sd_bus_message *m;
|
|
|
|
/* If this is an embedded creds structure, then
|
|
* forward ref counting to the message */
|
|
m = container_of(c, sd_bus_message, creds);
|
|
sd_bus_message_ref(m);
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
_public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
|
|
|
|
if (!c)
|
|
return NULL;
|
|
|
|
if (c->allocated) {
|
|
assert(c->n_ref > 0);
|
|
c->n_ref--;
|
|
|
|
if (c->n_ref == 0) {
|
|
free(c->comm);
|
|
free(c->tid_comm);
|
|
free(c->exe);
|
|
free(c->cmdline);
|
|
free(c->cgroup);
|
|
free(c->capability);
|
|
free(c->label);
|
|
free(c->unique_name);
|
|
free(c->cgroup_root);
|
|
free(c->description);
|
|
|
|
c->supplementary_gids = mfree(c->supplementary_gids);
|
|
|
|
c->well_known_names = strv_free(c->well_known_names);
|
|
|
|
bus_creds_done(c);
|
|
|
|
free(c);
|
|
}
|
|
} else {
|
|
sd_bus_message *m;
|
|
|
|
m = container_of(c, sd_bus_message, creds);
|
|
sd_bus_message_unref(m);
|
|
}
|
|
|
|
|
|
return NULL;
|
|
}
|
|
|
|
_public_ uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c) {
|
|
assert_return(c, 0);
|
|
|
|
return c->mask;
|
|
}
|
|
|
|
_public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
|
|
assert_return(c, 0);
|
|
|
|
return c->augmented;
|
|
}
|
|
|
|
sd_bus_creds* bus_creds_new(void) {
|
|
sd_bus_creds *c;
|
|
|
|
c = new0(sd_bus_creds, 1);
|
|
if (!c)
|
|
return NULL;
|
|
|
|
c->allocated = true;
|
|
c->n_ref = 1;
|
|
return c;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
|
|
sd_bus_creds *c;
|
|
int r;
|
|
|
|
assert_return(pid >= 0, -EINVAL);
|
|
assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (pid == 0)
|
|
pid = getpid_cached();
|
|
|
|
c = bus_creds_new();
|
|
if (!c)
|
|
return -ENOMEM;
|
|
|
|
r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
|
|
if (r < 0) {
|
|
sd_bus_creds_unref(c);
|
|
return r;
|
|
}
|
|
|
|
/* Check if the process existed at all, in case we haven't
|
|
* figured that out already */
|
|
if (!pid_is_alive(pid)) {
|
|
sd_bus_creds_unref(c);
|
|
return -ESRCH;
|
|
}
|
|
|
|
*ret = c;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(uid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_UID))
|
|
return -ENODATA;
|
|
|
|
*uid = c->uid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(euid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_EUID))
|
|
return -ENODATA;
|
|
|
|
*euid = c->euid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(suid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_SUID))
|
|
return -ENODATA;
|
|
|
|
*suid = c->suid;
|
|
return 0;
|
|
}
|
|
|
|
|
|
_public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(fsuid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_FSUID))
|
|
return -ENODATA;
|
|
|
|
*fsuid = c->fsuid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(gid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_GID))
|
|
return -ENODATA;
|
|
|
|
*gid = c->gid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(egid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_EGID))
|
|
return -ENODATA;
|
|
|
|
*egid = c->egid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(sgid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_SGID))
|
|
return -ENODATA;
|
|
|
|
*sgid = c->sgid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(fsgid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_FSGID))
|
|
return -ENODATA;
|
|
|
|
*fsgid = c->fsgid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(gids, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
|
|
return -ENODATA;
|
|
|
|
*gids = c->supplementary_gids;
|
|
return (int) c->n_supplementary_gids;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(pid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_PID))
|
|
return -ENODATA;
|
|
|
|
assert(c->pid > 0);
|
|
*pid = c->pid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ppid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_PPID))
|
|
return -ENODATA;
|
|
|
|
/* PID 1 has no parent process. Let's distinguish the case of
|
|
* not knowing and not having a parent process by the returned
|
|
* error code. */
|
|
if (c->ppid == 0)
|
|
return -ENXIO;
|
|
|
|
*ppid = c->ppid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(tid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_TID))
|
|
return -ENODATA;
|
|
|
|
assert(c->tid > 0);
|
|
*tid = c->tid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
|
|
return -ENODATA;
|
|
|
|
assert(c->label);
|
|
*ret = c->label;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_comm(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_COMM))
|
|
return -ENODATA;
|
|
|
|
assert(c->comm);
|
|
*ret = c->comm;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_TID_COMM))
|
|
return -ENODATA;
|
|
|
|
assert(c->tid_comm);
|
|
*ret = c->tid_comm;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_exe(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_EXE))
|
|
return -ENODATA;
|
|
|
|
if (!c->exe)
|
|
return -ENXIO;
|
|
|
|
*ret = c->exe;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_cgroup(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_CGROUP))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
*ret = c->cgroup;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_unit(sd_bus_creds *c, const char **ret) {
|
|
int r;
|
|
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_UNIT))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
|
|
if (!c->unit) {
|
|
const char *shifted;
|
|
|
|
r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = cg_path_get_unit(shifted, (char**) &c->unit);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
*ret = c->unit;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_user_unit(sd_bus_creds *c, const char **ret) {
|
|
int r;
|
|
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
|
|
if (!c->user_unit) {
|
|
const char *shifted;
|
|
|
|
r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = cg_path_get_user_unit(shifted, (char**) &c->user_unit);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
*ret = c->user_unit;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_slice(sd_bus_creds *c, const char **ret) {
|
|
int r;
|
|
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_SLICE))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
|
|
if (!c->slice) {
|
|
const char *shifted;
|
|
|
|
r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = cg_path_get_slice(shifted, (char**) &c->slice);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
*ret = c->slice;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_user_slice(sd_bus_creds *c, const char **ret) {
|
|
int r;
|
|
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_USER_SLICE))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
|
|
if (!c->user_slice) {
|
|
const char *shifted;
|
|
|
|
r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = cg_path_get_user_slice(shifted, (char**) &c->user_slice);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
*ret = c->user_slice;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_session(sd_bus_creds *c, const char **ret) {
|
|
int r;
|
|
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_SESSION))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
|
|
if (!c->session) {
|
|
const char *shifted;
|
|
|
|
r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = cg_path_get_session(shifted, (char**) &c->session);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
*ret = c->session;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_owner_uid(sd_bus_creds *c, uid_t *uid) {
|
|
const char *shifted;
|
|
int r;
|
|
|
|
assert_return(c, -EINVAL);
|
|
assert_return(uid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
|
|
return -ENODATA;
|
|
|
|
assert(c->cgroup);
|
|
|
|
r = cg_shift_path(c->cgroup, c->cgroup_root, &shifted);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
return cg_path_get_owner_uid(shifted, uid);
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_cmdline(sd_bus_creds *c, char ***cmdline) {
|
|
assert_return(c, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_CMDLINE))
|
|
return -ENODATA;
|
|
|
|
if (!c->cmdline)
|
|
return -ENXIO;
|
|
|
|
if (!c->cmdline_array) {
|
|
c->cmdline_array = strv_parse_nulstr(c->cmdline, c->cmdline_size);
|
|
if (!c->cmdline_array)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
*cmdline = c->cmdline_array;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(sessionid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
|
|
return -ENODATA;
|
|
|
|
if (!audit_session_is_valid(c->audit_session_id))
|
|
return -ENXIO;
|
|
|
|
*sessionid = c->audit_session_id;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(uid, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
|
|
return -ENODATA;
|
|
|
|
if (!uid_is_valid(c->audit_login_uid))
|
|
return -ENXIO;
|
|
|
|
*uid = c->audit_login_uid;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_tty(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_TTY))
|
|
return -ENODATA;
|
|
|
|
if (!c->tty)
|
|
return -ENXIO;
|
|
|
|
*ret = c->tty;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **unique_name) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(unique_name, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
|
|
return -ENODATA;
|
|
|
|
*unique_name = c->unique_name;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_known_names) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(well_known_names, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
|
|
return -ENODATA;
|
|
|
|
/* As a special hack we return the bus driver as well-known
|
|
* names list when this is requested. */
|
|
if (c->well_known_names_driver) {
|
|
static const char* const wkn[] = {
|
|
"org.freedesktop.DBus",
|
|
NULL
|
|
};
|
|
|
|
*well_known_names = (char**) wkn;
|
|
return 0;
|
|
}
|
|
|
|
if (c->well_known_names_local) {
|
|
static const char* const wkn[] = {
|
|
"org.freedesktop.DBus.Local",
|
|
NULL
|
|
};
|
|
|
|
*well_known_names = (char**) wkn;
|
|
return 0;
|
|
}
|
|
|
|
*well_known_names = c->well_known_names;
|
|
return 0;
|
|
}
|
|
|
|
_public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(ret, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
|
|
return -ENODATA;
|
|
|
|
assert(c->description);
|
|
|
|
if (!c->unescaped_description) {
|
|
c->unescaped_description = bus_label_unescape(c->description);
|
|
if (!c->unescaped_description)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
*ret = c->unescaped_description;
|
|
return 0;
|
|
}
|
|
|
|
static int has_cap(sd_bus_creds *c, unsigned offset, int capability) {
|
|
size_t sz;
|
|
|
|
assert(c);
|
|
assert(capability >= 0);
|
|
assert(c->capability);
|
|
|
|
if ((unsigned) capability > cap_last_cap())
|
|
return 0;
|
|
|
|
sz = DIV_ROUND_UP(cap_last_cap(), 32U);
|
|
|
|
return !!(c->capability[offset * sz + CAP_TO_INDEX(capability)] & CAP_TO_MASK(capability));
|
|
}
|
|
|
|
_public_ int sd_bus_creds_has_effective_cap(sd_bus_creds *c, int capability) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(capability >= 0, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
|
|
return -ENODATA;
|
|
|
|
return has_cap(c, CAP_OFFSET_EFFECTIVE, capability);
|
|
}
|
|
|
|
_public_ int sd_bus_creds_has_permitted_cap(sd_bus_creds *c, int capability) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(capability >= 0, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
|
|
return -ENODATA;
|
|
|
|
return has_cap(c, CAP_OFFSET_PERMITTED, capability);
|
|
}
|
|
|
|
_public_ int sd_bus_creds_has_inheritable_cap(sd_bus_creds *c, int capability) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(capability >= 0, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
|
|
return -ENODATA;
|
|
|
|
return has_cap(c, CAP_OFFSET_INHERITABLE, capability);
|
|
}
|
|
|
|
_public_ int sd_bus_creds_has_bounding_cap(sd_bus_creds *c, int capability) {
|
|
assert_return(c, -EINVAL);
|
|
assert_return(capability >= 0, -EINVAL);
|
|
|
|
if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
|
|
return -ENODATA;
|
|
|
|
return has_cap(c, CAP_OFFSET_BOUNDING, capability);
|
|
}
|
|
|
|
static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
|
|
size_t sz, max;
|
|
unsigned i, j;
|
|
|
|
assert(c);
|
|
assert(p);
|
|
|
|
max = DIV_ROUND_UP(cap_last_cap(), 32U);
|
|
p += strspn(p, WHITESPACE);
|
|
|
|
sz = strlen(p);
|
|
if (sz % 8 != 0)
|
|
return -EINVAL;
|
|
|
|
sz /= 8;
|
|
if (sz > max)
|
|
return -EINVAL;
|
|
|
|
if (!c->capability) {
|
|
c->capability = new0(uint32_t, max * 4);
|
|
if (!c->capability)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (i = 0; i < sz; i ++) {
|
|
uint32_t v = 0;
|
|
|
|
for (j = 0; j < 8; ++j) {
|
|
int t;
|
|
|
|
t = unhexchar(*p++);
|
|
if (t < 0)
|
|
return -EINVAL;
|
|
|
|
v = (v << 4) | t;
|
|
}
|
|
|
|
c->capability[offset * max + (sz - i - 1)] = v;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
|
|
uint64_t missing;
|
|
int r;
|
|
|
|
assert(c);
|
|
assert(c->allocated);
|
|
|
|
if (!(mask & SD_BUS_CREDS_AUGMENT))
|
|
return 0;
|
|
|
|
/* Try to retrieve PID from creds if it wasn't passed to us */
|
|
if (pid > 0) {
|
|
c->pid = pid;
|
|
c->mask |= SD_BUS_CREDS_PID;
|
|
} else if (c->mask & SD_BUS_CREDS_PID)
|
|
pid = c->pid;
|
|
else
|
|
/* Without pid we cannot do much... */
|
|
return 0;
|
|
|
|
/* Try to retrieve TID from creds if it wasn't passed to us */
|
|
if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID))
|
|
tid = c->tid;
|
|
|
|
/* Calculate what we shall and can add */
|
|
missing = mask & ~(c->mask|SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_AUGMENT);
|
|
if (missing == 0)
|
|
return 0;
|
|
|
|
if (tid > 0) {
|
|
c->tid = tid;
|
|
c->mask |= SD_BUS_CREDS_TID;
|
|
}
|
|
|
|
if (missing & (SD_BUS_CREDS_PPID |
|
|
SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
|
|
SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
|
|
SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
|
|
SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
|
|
SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
const char *p;
|
|
|
|
p = procfs_file_alloca(pid, "status");
|
|
|
|
f = fopen(p, "re");
|
|
if (!f) {
|
|
if (errno == ENOENT)
|
|
return -ESRCH;
|
|
else if (errno != EPERM && errno != EACCES)
|
|
return -errno;
|
|
} else {
|
|
char line[LINE_MAX];
|
|
|
|
FOREACH_LINE(line, f, return -errno) {
|
|
truncate_nl(line);
|
|
|
|
if (missing & SD_BUS_CREDS_PPID) {
|
|
p = startswith(line, "PPid:");
|
|
if (p) {
|
|
p += strspn(p, WHITESPACE);
|
|
|
|
/* Explicitly check for PPID 0 (which is the case for PID 1) */
|
|
if (!streq(p, "0")) {
|
|
r = parse_pid(p, &c->ppid);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
} else
|
|
c->ppid = 0;
|
|
|
|
c->mask |= SD_BUS_CREDS_PPID;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
|
|
p = startswith(line, "Uid:");
|
|
if (p) {
|
|
unsigned long uid, euid, suid, fsuid;
|
|
|
|
p += strspn(p, WHITESPACE);
|
|
if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
|
|
return -EIO;
|
|
|
|
if (missing & SD_BUS_CREDS_UID)
|
|
c->uid = (uid_t) uid;
|
|
if (missing & SD_BUS_CREDS_EUID)
|
|
c->euid = (uid_t) euid;
|
|
if (missing & SD_BUS_CREDS_SUID)
|
|
c->suid = (uid_t) suid;
|
|
if (missing & SD_BUS_CREDS_FSUID)
|
|
c->fsuid = (uid_t) fsuid;
|
|
|
|
c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
|
|
p = startswith(line, "Gid:");
|
|
if (p) {
|
|
unsigned long gid, egid, sgid, fsgid;
|
|
|
|
p += strspn(p, WHITESPACE);
|
|
if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
|
|
return -EIO;
|
|
|
|
if (missing & SD_BUS_CREDS_GID)
|
|
c->gid = (gid_t) gid;
|
|
if (missing & SD_BUS_CREDS_EGID)
|
|
c->egid = (gid_t) egid;
|
|
if (missing & SD_BUS_CREDS_SGID)
|
|
c->sgid = (gid_t) sgid;
|
|
if (missing & SD_BUS_CREDS_FSGID)
|
|
c->fsgid = (gid_t) fsgid;
|
|
|
|
c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
|
|
p = startswith(line, "Groups:");
|
|
if (p) {
|
|
size_t allocated = 0;
|
|
|
|
for (;;) {
|
|
unsigned long g;
|
|
int n = 0;
|
|
|
|
p += strspn(p, WHITESPACE);
|
|
if (*p == 0)
|
|
break;
|
|
|
|
if (sscanf(p, "%lu%n", &g, &n) != 1)
|
|
return -EIO;
|
|
|
|
if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
|
|
return -ENOMEM;
|
|
|
|
c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
|
|
p += n;
|
|
}
|
|
|
|
c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
|
|
p = startswith(line, "CapEff:");
|
|
if (p) {
|
|
r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
|
|
p = startswith(line, "CapPrm:");
|
|
if (p) {
|
|
r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
|
|
p = startswith(line, "CapInh:");
|
|
if (p) {
|
|
r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
|
|
p = startswith(line, "CapBnd:");
|
|
if (p) {
|
|
r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
|
|
const char *p;
|
|
|
|
p = procfs_file_alloca(pid, "attr/current");
|
|
r = read_one_line_file(p, &c->label);
|
|
if (r < 0) {
|
|
if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_COMM) {
|
|
r = get_process_comm(pid, &c->comm);
|
|
if (r < 0) {
|
|
if (r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_COMM;
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_EXE) {
|
|
r = get_process_exe(pid, &c->exe);
|
|
if (r == -ESRCH) {
|
|
/* Unfortunately we cannot really distinguish
|
|
* the case here where the process does not
|
|
* exist, and /proc/$PID/exe being unreadable
|
|
* because $PID is a kernel thread. Hence,
|
|
* assume it is a kernel thread, and rely on
|
|
* that this case is caught with a later
|
|
* call. */
|
|
c->exe = NULL;
|
|
c->mask |= SD_BUS_CREDS_EXE;
|
|
} else if (r < 0) {
|
|
if (r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_EXE;
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_CMDLINE) {
|
|
const char *p;
|
|
|
|
p = procfs_file_alloca(pid, "cmdline");
|
|
r = read_full_file(p, &c->cmdline, &c->cmdline_size);
|
|
if (r == -ENOENT)
|
|
return -ESRCH;
|
|
if (r < 0) {
|
|
if (r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else {
|
|
if (c->cmdline_size == 0)
|
|
c->cmdline = mfree(c->cmdline);
|
|
|
|
c->mask |= SD_BUS_CREDS_CMDLINE;
|
|
}
|
|
}
|
|
|
|
if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
|
|
return -ENOMEM;
|
|
|
|
r = read_one_line_file(p, &c->tid_comm);
|
|
if (r == -ENOENT)
|
|
return -ESRCH;
|
|
if (r < 0) {
|
|
if (r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_TID_COMM;
|
|
}
|
|
|
|
if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
|
|
|
|
if (!c->cgroup) {
|
|
r = cg_pid_get_path(NULL, pid, &c->cgroup);
|
|
if (r < 0) {
|
|
if (r != -EPERM && r != -EACCES)
|
|
return r;
|
|
}
|
|
}
|
|
|
|
if (!c->cgroup_root) {
|
|
r = cg_get_root_path(&c->cgroup_root);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
if (c->cgroup)
|
|
c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
|
|
r = audit_session_from_pid(pid, &c->audit_session_id);
|
|
if (r == -ENODATA) {
|
|
/* ENODATA means: no audit session id assigned */
|
|
c->audit_session_id = AUDIT_SESSION_INVALID;
|
|
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
|
|
} else if (r < 0) {
|
|
if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
|
|
r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
|
|
if (r == -ENODATA) {
|
|
/* ENODATA means: no audit login uid assigned */
|
|
c->audit_login_uid = UID_INVALID;
|
|
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
|
|
} else if (r < 0) {
|
|
if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
|
|
}
|
|
|
|
if (missing & SD_BUS_CREDS_TTY) {
|
|
r = get_ctty(pid, NULL, &c->tty);
|
|
if (r == -ENXIO) {
|
|
/* ENXIO means: process has no controlling TTY */
|
|
c->tty = NULL;
|
|
c->mask |= SD_BUS_CREDS_TTY;
|
|
} else if (r < 0) {
|
|
if (r != -EPERM && r != -EACCES && r != -ENOENT)
|
|
return r;
|
|
} else
|
|
c->mask |= SD_BUS_CREDS_TTY;
|
|
}
|
|
|
|
/* In case only the exe path was to be read we cannot
|
|
* distinguish the case where the exe path was unreadable
|
|
* because the process was a kernel thread, or when the
|
|
* process didn't exist at all. Hence, let's do a final check,
|
|
* to be sure. */
|
|
if (!pid_is_alive(pid))
|
|
return -ESRCH;
|
|
|
|
if (tid > 0 && tid != pid && !pid_is_unwaited(tid))
|
|
return -ESRCH;
|
|
|
|
c->augmented = missing & c->mask;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) {
|
|
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *n = NULL;
|
|
int r;
|
|
|
|
assert(c);
|
|
assert(ret);
|
|
|
|
if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
|
|
/* There's already all data we need, or augmentation
|
|
* wasn't turned on. */
|
|
|
|
*ret = sd_bus_creds_ref(c);
|
|
return 0;
|
|
}
|
|
|
|
n = bus_creds_new();
|
|
if (!n)
|
|
return -ENOMEM;
|
|
|
|
/* Copy the original data over */
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_PID) {
|
|
n->pid = c->pid;
|
|
n->mask |= SD_BUS_CREDS_PID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_TID) {
|
|
n->tid = c->tid;
|
|
n->mask |= SD_BUS_CREDS_TID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_PPID) {
|
|
n->ppid = c->ppid;
|
|
n->mask |= SD_BUS_CREDS_PPID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_UID) {
|
|
n->uid = c->uid;
|
|
n->mask |= SD_BUS_CREDS_UID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_EUID) {
|
|
n->euid = c->euid;
|
|
n->mask |= SD_BUS_CREDS_EUID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_SUID) {
|
|
n->suid = c->suid;
|
|
n->mask |= SD_BUS_CREDS_SUID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_FSUID) {
|
|
n->fsuid = c->fsuid;
|
|
n->mask |= SD_BUS_CREDS_FSUID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_GID) {
|
|
n->gid = c->gid;
|
|
n->mask |= SD_BUS_CREDS_GID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_EGID) {
|
|
n->egid = c->egid;
|
|
n->mask |= SD_BUS_CREDS_EGID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_SGID) {
|
|
n->sgid = c->sgid;
|
|
n->mask |= SD_BUS_CREDS_SGID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_FSGID) {
|
|
n->fsgid = c->fsgid;
|
|
n->mask |= SD_BUS_CREDS_FSGID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
|
|
if (c->supplementary_gids) {
|
|
n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
|
|
if (!n->supplementary_gids)
|
|
return -ENOMEM;
|
|
n->n_supplementary_gids = c->n_supplementary_gids;
|
|
} else {
|
|
n->supplementary_gids = NULL;
|
|
n->n_supplementary_gids = 0;
|
|
}
|
|
|
|
n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_COMM) {
|
|
assert(c->comm);
|
|
|
|
n->comm = strdup(c->comm);
|
|
if (!n->comm)
|
|
return -ENOMEM;
|
|
|
|
n->mask |= SD_BUS_CREDS_COMM;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_TID_COMM) {
|
|
assert(c->tid_comm);
|
|
|
|
n->tid_comm = strdup(c->tid_comm);
|
|
if (!n->tid_comm)
|
|
return -ENOMEM;
|
|
|
|
n->mask |= SD_BUS_CREDS_TID_COMM;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_EXE) {
|
|
if (c->exe) {
|
|
n->exe = strdup(c->exe);
|
|
if (!n->exe)
|
|
return -ENOMEM;
|
|
} else
|
|
n->exe = NULL;
|
|
|
|
n->mask |= SD_BUS_CREDS_EXE;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_CMDLINE) {
|
|
if (c->cmdline) {
|
|
n->cmdline = memdup(c->cmdline, c->cmdline_size);
|
|
if (!n->cmdline)
|
|
return -ENOMEM;
|
|
|
|
n->cmdline_size = c->cmdline_size;
|
|
} else {
|
|
n->cmdline = NULL;
|
|
n->cmdline_size = 0;
|
|
}
|
|
|
|
n->mask |= SD_BUS_CREDS_CMDLINE;
|
|
}
|
|
|
|
if (c->mask & mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_OWNER_UID)) {
|
|
assert(c->cgroup);
|
|
|
|
n->cgroup = strdup(c->cgroup);
|
|
if (!n->cgroup)
|
|
return -ENOMEM;
|
|
|
|
n->cgroup_root = strdup(c->cgroup_root);
|
|
if (!n->cgroup_root)
|
|
return -ENOMEM;
|
|
|
|
n->mask |= mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_OWNER_UID);
|
|
}
|
|
|
|
if (c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)) {
|
|
assert(c->capability);
|
|
|
|
n->capability = memdup(c->capability, DIV_ROUND_UP(cap_last_cap(), 32U) * 4 * 4);
|
|
if (!n->capability)
|
|
return -ENOMEM;
|
|
|
|
n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
|
|
assert(c->label);
|
|
|
|
n->label = strdup(c->label);
|
|
if (!n->label)
|
|
return -ENOMEM;
|
|
n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
|
|
n->audit_session_id = c->audit_session_id;
|
|
n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
|
|
}
|
|
if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
|
|
n->audit_login_uid = c->audit_login_uid;
|
|
n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_TTY) {
|
|
if (c->tty) {
|
|
n->tty = strdup(c->tty);
|
|
if (!n->tty)
|
|
return -ENOMEM;
|
|
} else
|
|
n->tty = NULL;
|
|
n->mask |= SD_BUS_CREDS_TTY;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_UNIQUE_NAME) {
|
|
assert(c->unique_name);
|
|
|
|
n->unique_name = strdup(c->unique_name);
|
|
if (!n->unique_name)
|
|
return -ENOMEM;
|
|
n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
|
|
if (strv_isempty(c->well_known_names))
|
|
n->well_known_names = NULL;
|
|
else {
|
|
n->well_known_names = strv_copy(c->well_known_names);
|
|
if (!n->well_known_names)
|
|
return -ENOMEM;
|
|
}
|
|
n->well_known_names_driver = c->well_known_names_driver;
|
|
n->well_known_names_local = c->well_known_names_local;
|
|
n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
|
|
}
|
|
|
|
if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
|
|
assert(c->description);
|
|
n->description = strdup(c->description);
|
|
if (!n->description)
|
|
return -ENOMEM;
|
|
n->mask |= SD_BUS_CREDS_DESCRIPTION;
|
|
}
|
|
|
|
n->augmented = c->augmented & n->mask;
|
|
|
|
/* Get more data */
|
|
|
|
r = bus_creds_add_more(n, mask, 0, 0);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
*ret = n;
|
|
n = NULL;
|
|
return 0;
|
|
}
|