/* details= */ NULL,
/* good_user= */ FLAGS_SET(arg_flags, ASK_PASSWORD_USER) ? getuid() : UID_INVALID,
/* flags= */ 0,
- polkit_registry);
+ polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
good_uid,
/* flags= */ 0,
&h->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
}
h->uid,
/* flags= */ 0,
&h->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
/* flags= */ 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
/* flags= */ 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* details= */ NULL,
UID_INVALID,
POLKIT_DONT_REPLY,
- &c->polkit_registry);
+ &c->polkit_registry,
+ /* ret_admin= */ NULL);
if (r == 0)
return 0; /* No authorization for now, but the async polkit stuff will call us again when it has it */
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
s->user->user_record->uid,
/* flags= */ 0,
&s->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
s->user->user_record->uid,
/* flags= */ 0,
&s->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
s->user->user_record->uid,
/* flags= */ 0,
&s->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
else
r = varlink_verify_polkit_async_full(
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
- &m->polkit_registry);
+ &m->polkit_registry,
+ /* ret_admin= */ NULL);
if (r < 0) {
/* If we get -EBUSY, it means a polkit decision was made, but not for
/* good_user= */ UID_INVALID,
polkit_flags,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
else
r = varlink_verify_polkit_async_full(
/* details= */ NULL,
/* good_user= */ UID_INVALID,
polkit_flags,
- &m->polkit_registry);
+ &m->polkit_registry,
+ /* ret_admin= */ NULL);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
else
r = varlink_verify_polkit_async_full(
/* details= */ NULL,
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
- &m->polkit_registry);
+ &m->polkit_registry,
+ /* ret_admin= */ NULL);
if (r < 0)
return r;
u->user_record->uid,
/* flags= */ 0,
&u->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
u->user_record->uid,
/* flags= */ 0,
&u->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
m->uid,
/* flags= */ 0,
&m->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
m->uid,
/* flags= */ 0,
&m->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
m->uid,
/* flags= */ 0,
&m->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
m->uid,
/* flags= */ 0,
&m->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
m->uid,
/* flags= */ 0,
&m->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
m->uid,
/* flags= */ 0,
&m->manager->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
"verb", "unregister"),
machine->uid,
/* flags= */ 0,
- &manager->polkit_registry);
+ &manager->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
}
"verb", "terminate"),
machine->uid,
/* flags= */ 0,
- &manager->polkit_registry);
+ &manager->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
}
"verb", "kill"),
machine->uid,
/* flags= */ 0,
- &manager->polkit_registry);
+ &manager->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
}
(const char**) polkit_details,
machine->uid,
/* flags= */ 0,
- &manager->polkit_registry);
+ &manager->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
}
polkit_details,
/* good_user= */ UID_INVALID,
polkit_flags,
- polkit_registry);
+ polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
/* Let's see if we have acquired the privilege to mount untrusted images already */
bool polkit_have_untrusted_action =
- varlink_has_polkit_action(link, polkit_untrusted_action, polkit_details, polkit_registry);
+ varlink_has_polkit_action(link, polkit_untrusted_action, polkit_details, polkit_registry, /* ret_admin= */ NULL);
for (;;) {
use_policy = image_policy_free(use_policy);
polkit_details,
/* good_user= */ UID_INVALID,
/* flags= */ 0, /* NB: the image cannot be authenticated, hence unless PK is around to allow this anyway, fail! */
- polkit_registry);
+ polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0 && !ERRNO_IS_NEG_PRIVILEGE(r))
return r;
if (r > 0) {
polkit_details,
/* good_user= */ UID_INVALID,
/* flags= */ 0, /* NB: the image cannot be authenticated, hence unless PK is around to allow this anyway, fail! */
- polkit_registry);
+ polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0 && !ERRNO_IS_NEG_PRIVILEGE(r))
return r;
if (r > 0) {
polkit_details,
/* good_user= */ UID_INVALID,
trusted_directory ? polkit_flags : 0,
- polkit_registry);
+ polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
polkit_details,
/* good_user= */ UID_INVALID,
polkit_flags,
- polkit_registry);
+ polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
polkit_details,
/* good_user= */ UID_INVALID,
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow unpriv userns namespace allocation */
- &c->polkit_registry);
+ &c->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
polkit_details,
/* good_user= */ UID_INVALID,
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow unpriv userns namespace registration */
- &c->polkit_registry);
+ &c->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
/* details= */ NULL,
/* good_user= */ UID_INVALID,
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow delegation of mounts to registered userns */
- &c->polkit_registry);
+ &c->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
/* details= */ NULL,
/* good_user= */ UID_INVALID,
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow delegation of cgroups to registered userns */
- &c->polkit_registry);
+ &c->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
polkit_details,
/* good_user= */ UID_INVALID,
POLKIT_DEFAULT_ALLOW, /* If no polkit is installed, allow delegation of network interfaces to registered userns */
- &c->polkit_registry);
+ &c->polkit_registry,
+ /* ret_admin= */ NULL);
if (r <= 0)
return r;
/* good_user= */ s->originator,
/* flags= */ 0,
&m->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
#include "strv.h"
#include "varlink-util.h"
-static int bus_message_check_good_user(sd_bus_message *m, uid_t good_user) {
+static int bus_message_check_good_user(sd_bus_message *m, uid_t good_user, bool *ret_admin) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
uid_t sender_uid;
int r;
assert(m);
- if (good_user == UID_INVALID)
+ if (good_user == UID_INVALID) {
+ if (ret_admin)
+ *ret_admin = false;
return false;
+ }
r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
if (r < 0)
return r;
+ if (ret_admin)
+ *ret_admin = sender_uid == 0;
+
return sender_uid == good_user;
}
/* Tests non-interactively! */
- r = bus_message_check_good_user(call, good_user);
+ r = bus_message_check_good_user(call, good_user, /* ret_admin= */ NULL);
if (r != 0)
return r;
typedef struct AsyncPolkitQueryAction {
char *action;
char **details;
+ bool admin; /* true when the action was authorized by auth_admin/auth_admin_keep (i.e.: by a privileged user) */
LIST_FIELDS(struct AsyncPolkitQueryAction, authorized);
} AsyncPolkitQueryAction;
}
r = sd_bus_message_enter_container(reply, 'r', "bba{ss}");
- if (r >= 0)
- r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
+ if (r < 0)
+ return r;
+ r = sd_bus_message_read(reply, "bb", &authorized, &challenge);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_enter_container(reply, 'a', "{ss}");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ const char *k, *v;
+
+ r = sd_bus_message_enter_container(reply, 'e', "ss");
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_read(reply, "ss", &k, &v);
+ if (r < 0)
+ return r;
+ if (r > 0 && streq(k, "polkit.result") && STR_IN_SET(v, "auth_admin_keep", "auth_admin"))
+ a->admin = true;
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
if (r < 0)
return r;
static bool async_polkit_query_have_action(
AsyncPolkitQuery *q,
const char *action,
- const char **details) {
+ const char **details,
+ /* Reports whether the subject authenticated as admin, instead of a regular user */
+ bool *ret_admin) {
assert(q);
assert(action);
LIST_FOREACH(authorized, a, q->authorized_actions)
- if (streq(a->action, action) && strv_equal(a->details, (char**) details))
+ if (streq(a->action, action) && strv_equal(a->details, (char**) details)) {
+ if (ret_admin)
+ *ret_admin = a->admin;
return true;
+ }
+
+ if (ret_admin)
+ *ret_admin = false;
return false;
}
const char *action,
const char **details,
PolkitFlags flags,
+ bool *ret_admin,
sd_bus_error *reterr_error) {
+ bool admin = false; /* Not privileged until proven otherwise */
+
assert(q);
assert(action);
- if (async_polkit_query_have_action(q, action, details))
+ if (async_polkit_query_have_action(q, action, details, &admin)) {
+ if (ret_admin)
+ *ret_admin = admin;
return 1; /* Allow! */
+ }
if (q->error_action && streq(q->error_action->action, action))
return sd_bus_error_copy(reterr_error, &q->error);
if (q->denied_action && streq(q->denied_action->action, action))
return -EACCES; /* Deny! */
- if (q->absent_action)
- return FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW) ? 1 /* Allow! */ : -EACCES /* Deny! */;
+ if (q->absent_action) {
+ if (!FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW))
+ return -EACCES;
+ if (ret_admin)
+ *ret_admin = admin;
+ return 1;
+ }
/* Also deny if we've got an auth. failure for a previous action */
if (q->denied_action || q->error_action)
return -EBUSY;
+ if (ret_admin)
+ *ret_admin = admin;
+
return 0; /* no reply yet */
}
#endif
uid_t good_user,
PolkitFlags flags,
Hashmap **registry,
+ bool *ret_admin,
sd_bus_error *reterr_error) {
+ bool admin = false; /* Not privileged until proven otherwise */
int r;
assert(call);
log_debug("Trying to acquire polkit authentication for '%s'.", action);
- r = bus_message_check_good_user(call, good_user);
- if (r != 0)
+ r = bus_message_check_good_user(call, good_user, &admin);
+ if (r != 0) {
+ if (r > 0 && ret_admin)
+ *ret_admin = admin;
return r;
+ }
#if ENABLE_POLKIT
_cleanup_(async_polkit_query_unrefp) AsyncPolkitQuery *q = NULL;
/* This is a repeated invocation of this function, hence let's check if we've already got
* a response from polkit for this action */
if (q) {
- r = async_polkit_query_check_action(q, action, details, flags, reterr_error);
+ r = async_polkit_query_check_action(q, action, details, flags, &admin, reterr_error);
if (r != 0) {
+ if (r > 0 && ret_admin)
+ *ret_admin = admin;
log_debug("Found matching previous polkit authentication for '%s'.", action);
return r;
}
r = sd_bus_query_sender_privilege(call, /* capability= */ -1);
if (r < 0)
return r;
- if (r > 0)
+ if (r > 0) {
+ if (ret_admin)
+ *ret_admin = true;
return 1;
+ }
#if ENABLE_POLKIT
}
TAKE_PTR(q);
+ if (ret_admin)
+ *ret_admin = admin;
+
return 0;
#else
- return FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW) ? 1 : -EACCES;
+ if (!FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW))
+ return -EACCES;
+ if (ret_admin)
+ *ret_admin = admin;
+ return 1;
#endif
}
-static int varlink_check_good_user(sd_varlink *link, uid_t good_user) {
+static int varlink_check_good_user(sd_varlink *link, uid_t good_user, bool *ret_admin) {
int r;
assert(link);
- if (good_user == UID_INVALID)
+ if (good_user == UID_INVALID) {
+ if (ret_admin)
+ *ret_admin = false;
return false;
+ }
uid_t peer_uid;
r = sd_varlink_get_peer_uid(link, &peer_uid);
if (r < 0)
return r;
+ if (ret_admin)
+ *ret_admin = peer_uid == 0;
+
return good_user == peer_uid;
}
const char **details,
uid_t good_user,
PolkitFlags flags,
- Hashmap **registry) {
+ Hashmap **registry,
+ bool *ret_admin) {
+ bool admin = false; /* Not privileged until proven otherwise */
int r;
assert(link);
/* This is the same as bus_verify_polkit_async_full(), but authenticates the peer of a varlink
* connection rather than the sender of a bus message. */
- r = varlink_check_good_user(link, good_user);
- if (r != 0)
+ r = varlink_check_good_user(link, good_user, &admin);
+ if (r != 0) {
+ if (r > 0 && ret_admin)
+ *ret_admin = admin;
return r;
+ }
#if ENABLE_POLKIT
if (!FLAGS_SET(flags, POLKIT_ALWAYS_QUERY)) {
#endif
r = varlink_check_peer_privilege(link);
- if (r != 0)
+ if (r != 0) {
+ if (r > 0 && ret_admin)
+ *ret_admin = true;
return r;
+ }
#if ENABLE_POLKIT
}
* a response from polkit for this action */
if (q) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- r = async_polkit_query_check_action(q, action, details, flags, &error);
+ r = async_polkit_query_check_action(q, action, details, flags, &admin, &error);
if (r != 0)
log_debug("Found matching previous polkit authentication for '%s'.", action);
if (r < 0) {
return r;
}
- if (r > 0)
+ if (r > 0) {
+ if (ret_admin)
+ *ret_admin = admin;
return r;
+ }
}
_cleanup_(sd_bus_unrefp) sd_bus *mybus = NULL;
TAKE_PTR(q);
+ if (ret_admin)
+ *ret_admin = admin;
+
return 0;
#else
- return FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW) ? 1 : -EACCES;
+ if (!FLAGS_SET(flags, POLKIT_DEFAULT_ALLOW))
+ return -EACCES;
+ if (ret_admin)
+ *ret_admin = admin;
+ return 1;
#endif
}
-bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry) {
+bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry, bool *ret_admin) {
assert(link);
assert(action);
assert(registry);
if (!q)
return false;
- return async_polkit_query_have_action(q, action, details);
+ return async_polkit_query_have_action(q, action, details, ret_admin);
#else
+ if (ret_admin)
+ *ret_admin = false; /* Not privileged until proven otherwise */
return false;
#endif
}
int bus_test_polkit(sd_bus_message *call, const char *action, const char **details, uid_t good_user, bool *ret_challenge, sd_bus_error *reterr_error);
-int bus_verify_polkit_async_full(sd_bus_message *call, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry, sd_bus_error *reterr_error);
+int bus_verify_polkit_async_full(sd_bus_message *call, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry, bool *ret_admin, sd_bus_error *reterr_error);
static inline int bus_verify_polkit_async(sd_bus_message *call, const char *action, const char **details, Hashmap **registry, sd_bus_error *reterr_error) {
- return bus_verify_polkit_async_full(call, action, details, UID_INVALID, 0, registry, reterr_error);
+ return bus_verify_polkit_async_full(call, action, details, UID_INVALID, 0, registry, NULL, reterr_error);
}
-int varlink_verify_polkit_async_full(sd_varlink *link, sd_bus *bus, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry);
+int varlink_verify_polkit_async_full(sd_varlink *link, sd_bus *bus, const char *action, const char **details, uid_t good_user, PolkitFlags flags, Hashmap **registry, bool *ret_admin);
static inline int varlink_verify_polkit_async(sd_varlink *link, sd_bus *bus, const char *action, const char **details, Hashmap **registry) {
- return varlink_verify_polkit_async_full(link, bus, action, details, UID_INVALID, 0, registry);
+ return varlink_verify_polkit_async_full(link, bus, action, details, UID_INVALID, 0, registry, NULL);
}
/* A sd_json_dispatch_field initializer that makes sure the allowInteractiveAuthentication boolean field we want for
SD_VARLINK_FIELD_COMMENT("Controls whether interactive authentication (via polkit) shall be allowed. If unspecified defaults to false."), \
SD_VARLINK_DEFINE_INPUT(allowInteractiveAuthentication, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE)
-bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry);
+bool varlink_has_polkit_action(sd_varlink *link, const char *action, const char **details, Hashmap **registry, bool *ret_admin);
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;
/* good_user= */ UID_INVALID,
interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
+ /* ret_admin= */ NULL,
error);
if (r < 0)
return r;