bus-creds.c revision 0f51442056157cfec2efc52ddbff7392b0ff674a
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
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 <stdlib.h>
#include <linux/capability.h>
#include "util.h"
#include "formats-util.h"
#include "process-util.h"
#include "capability.h"
#include "cgroup-util.h"
#include "fileio.h"
#include "audit.h"
#include "bus-message.h"
#include "bus-util.h"
#include "strv.h"
#include "bus-creds.h"
#include "bus-label.h"
enum {
CAP_OFFSET_PERMITTED = 1,
CAP_OFFSET_EFFECTIVE = 2,
};
void bus_creds_done(sd_bus_creds *c) {
assert(c);
/* For internal bus cred structures that are allocated by
* something else */
free(c->supplementary_gids);
* 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);
}
assert_return(c, NULL);
if (c->allocated) {
c->n_ref++;
} else {
sd_bus_message *m;
/* If this is an embedded creds structure, then
* forward ref counting to the message */
}
return c;
}
if (!c)
return NULL;
if (c->allocated) {
c->n_ref--;
if (c->n_ref == 0) {
free(c->capability);
free(c->unique_name);
free(c->cgroup_root);
free(c->description);
free(c->supplementary_gids);
c->supplementary_gids = NULL;
c->well_known_names = NULL;
bus_creds_done(c);
free(c);
}
} else {
sd_bus_message *m;
}
return NULL;
}
assert_return(c, 0);
return c->mask;
}
assert_return(c, 0);
return c->augmented;
}
sd_bus_creds* bus_creds_new(void) {
sd_bus_creds *c;
if (!c)
return NULL;
c->allocated = true;
c->n_ref = 1;
return c;
}
sd_bus_creds *c;
int r;
if (pid == 0)
c = bus_creds_new();
if (!c)
return -ENOMEM;
if (r < 0) {
return r;
}
/* Check if the process existed at all, in case we haven't
* figured that out already */
if (!pid_is_alive(pid)) {
return -ESRCH;
}
*ret = c;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_UID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_EUID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_SUID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_FSUID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_GID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_EGID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_SGID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_FSGID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
return -ENODATA;
*gids = c->supplementary_gids;
return (int) c->n_supplementary_gids;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_PID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_TID))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_COMM))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_TID_COMM))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_EXE))
return -ENODATA;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_CGROUP))
return -ENODATA;
return 0;
}
int r;
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_UNIT))
return -ENODATA;
if (!c->unit) {
const char *shifted;
if (r < 0)
return r;
if (r < 0)
return r;
}
return 0;
}
int r;
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_USER_UNIT))
return -ENODATA;
if (!c->user_unit) {
const char *shifted;
if (r < 0)
return r;
if (r < 0)
return r;
}
return 0;
}
int r;
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_SLICE))
return -ENODATA;
if (!c->slice) {
const char *shifted;
if (r < 0)
return r;
if (r < 0)
return r;
}
return 0;
}
int r;
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_SESSION))
return -ENODATA;
if (!c->session) {
const char *shifted;
if (r < 0)
return r;
if (r < 0)
return r;
}
return 0;
}
const char *shifted;
int r;
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_OWNER_UID))
return -ENODATA;
if (r < 0)
return r;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_CMDLINE))
return -ENODATA;
if (!c->cmdline_array) {
if (!c->cmdline_array)
return -ENOMEM;
}
*cmdline = c->cmdline_array;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
return -ENODATA;
*sessionid = c->audit_session_id;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
return -ENODATA;
*uid = c->audit_login_uid;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_UNIQUE_NAME))
return -ENODATA;
*unique_name = c->unique_name;
return 0;
}
assert_return(c, -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",
};
*well_known_names = (char**) wkn;
return 0;
}
if (c->well_known_names_local) {
static const char* const wkn[] = {
"org.freedesktop.DBus.Local",
};
*well_known_names = (char**) wkn;
return 0;
}
*well_known_names = c->well_known_names;
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
return -ENODATA;
assert(c->description);
if (!c->unescaped_description) {
if (!c->unescaped_description)
return -ENOMEM;
}
*ret = c->unescaped_description;
return 0;
}
assert(c);
assert(capability >= 0);
assert(c->capability);
if ((unsigned) capability > cap_last_cap())
return 0;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_EFFECTIVE_CAPS))
return -ENODATA;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_PERMITTED_CAPS))
return -ENODATA;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_INHERITABLE_CAPS))
return -ENODATA;
}
assert_return(c, -EINVAL);
if (!(c->mask & SD_BUS_CREDS_BOUNDING_CAPS))
return -ENODATA;
}
unsigned i, j;
assert(c);
assert(p);
p += strspn(p, WHITESPACE);
if (sz % 8 != 0)
return -EINVAL;
sz /= 8;
return -EINVAL;
if (!c->capability) {
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;
}
}
return 0;
}
int r;
assert(c);
if (!(mask & SD_BUS_CREDS_AUGMENT))
return 0;
/* Try to retrieve PID from creds if it wasn't passed to us */
/* Without pid we cannot do much... */
if (pid <= 0)
return 0;
/* Try to retrieve TID from creds if it wasn't passed to us */
/* 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;
c->mask |= SD_BUS_CREDS_PID;
if (tid > 0) {
c->mask |= SD_BUS_CREDS_TID;
}
const char *p;
f = fopen(p, "re");
if (!f) {
return -ESRCH;
return -errno;
} else {
if (p) {
p += strspn(p, WHITESPACE);
return -EIO;
if (missing & SD_BUS_CREDS_UID)
if (missing & SD_BUS_CREDS_EUID)
if (missing & SD_BUS_CREDS_SUID)
if (missing & SD_BUS_CREDS_FSUID)
continue;
}
}
if (p) {
p += strspn(p, WHITESPACE);
return -EIO;
if (missing & SD_BUS_CREDS_GID)
if (missing & SD_BUS_CREDS_EGID)
if (missing & SD_BUS_CREDS_SGID)
if (missing & SD_BUS_CREDS_FSGID)
continue;
}
}
if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
if (p) {
for (;;) {
unsigned long g;
int n = 0;
p += strspn(p, WHITESPACE);
if (*p == 0)
break;
return -EIO;
return -ENOMEM;
p += n;
}
continue;
}
}
if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
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) {
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) {
if (p) {
r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
if (r < 0)
return r;
continue;
}
}
if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
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;
r = read_one_line_file(p, &c->label);
if (r < 0) {
return r;
} else
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
if (missing & SD_BUS_CREDS_COMM) {
if (r < 0) {
return r;
} else
c->mask |= SD_BUS_CREDS_COMM;
}
if (missing & SD_BUS_CREDS_EXE) {
if (r < 0) {
return r;
} else
c->mask |= SD_BUS_CREDS_EXE;
}
if (missing & SD_BUS_CREDS_CMDLINE) {
const char *p;
if (r < 0) {
if (r == -ENOENT)
return -ESRCH;
return r;
} else {
if (c->cmdline_size == 0) {
} else
c->mask |= SD_BUS_CREDS_CMDLINE;
}
}
_cleanup_free_ char *p = NULL;
return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm);
if (r < 0) {
if (r == -ENOENT)
return -ESRCH;
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_SESSION|SD_BUS_CREDS_OWNER_UID)) {
if (!c->cgroup) {
if (r < 0) {
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_SESSION|SD_BUS_CREDS_OWNER_UID);
}
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
if (r < 0) {
return r;
} else
}
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
if (r < 0) {
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
return 0;
}
int r;
assert(c);
/* 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 */
n->mask |= SD_BUS_CREDS_PID;
}
n->mask |= SD_BUS_CREDS_TID;
}
n->mask |= SD_BUS_CREDS_UID;
}
n->mask |= SD_BUS_CREDS_EUID;
}
n->mask |= SD_BUS_CREDS_SUID;
}
n->mask |= SD_BUS_CREDS_FSUID;
}
n->mask |= SD_BUS_CREDS_GID;
}
n->mask |= SD_BUS_CREDS_EGID;
}
n->mask |= SD_BUS_CREDS_SGID;
}
n->mask |= SD_BUS_CREDS_FSGID;
}
if (!n->supplementary_gids)
return -ENOMEM;
n->n_supplementary_gids = c->n_supplementary_gids;
}
if (!n->comm)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_COMM;
}
if (!n->tid_comm)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_TID_COMM;
}
if (!n->exe)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_EXE;
}
if (!n->cmdline)
return -ENOMEM;
n->cmdline_size = c->cmdline_size;
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_OWNER_UID)) {
if (!n->cgroup)
return -ENOMEM;
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_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)) {
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 (!n->label)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
n->audit_session_id = c->audit_session_id;
}
n->audit_login_uid = c->audit_login_uid;
n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
if (!n->unique_name)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
if (!n->well_known_names)
return -ENOMEM;
}
if (!n->description)
return -ENOMEM;
n->mask |= SD_BUS_CREDS_DESCRIPTION;
}
/* Get more data */
r = bus_creds_add_more(n, mask, 0, 0);
if (r < 0)
return r;
*ret = n;
n = NULL;
return 0;
}