/* Any time an access gets denied this callback will be called with the audit data. We then need to just copy the audit data into the msgbuf. */ static int audit_callback( void *auditdata, security_class_t cls, char *msgbuf, size_t msgbufsize) { const struct audit_info *audit = auditdata; uid_t uid = 0, login_uid = 0; gid_t gid = 0; char login_uid_buf[DECIMAL_STR_MAX(uid_t)] = "n/a"; char uid_buf[DECIMAL_STR_MAX(uid_t)] = "n/a"; char gid_buf[DECIMAL_STR_MAX(gid_t)] = "n/a"; if (sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid) >= 0) snprintf(login_uid_buf, sizeof(login_uid_buf), UID_FMT, login_uid); if (sd_bus_creds_get_uid(audit->creds, &uid) >= 0) snprintf(uid_buf, sizeof(uid_buf), UID_FMT, uid); if (sd_bus_creds_get_gid(audit->creds, &gid) >= 0) snprintf(gid_buf, sizeof(gid_buf), GID_FMT, gid); snprintf(msgbuf, msgbufsize, "auid=%s uid=%s gid=%s%s%s%s%s%s%s", login_uid_buf, uid_buf, gid_buf, audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "", audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : ""); msgbuf[msgbufsize-1] = 0; return 0; }
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t our_uid; int r; assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); assert_return(call->bus, -EINVAL); assert_return(!bus_pid_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; /* We only trust the effective capability set if this is * kdbus. On classic dbus1 we cannot retrieve the value * without races. Since this function is supposed to be useful * for authentication decision we hence avoid requesting and * using that information. */ if (call->bus->is_kernel && capability >= 0) { r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds); if (r < 0) return r; r = sd_bus_creds_has_effective_cap(creds, capability); if (r > 0) return 1; } else { r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID, &creds); if (r < 0) return r; } /* Now, check the UID, but only if the capability check wasn't * sufficient */ our_uid = getuid(); if (our_uid != 0 || !call->bus->is_kernel || capability < 0) { uid_t sender_uid; r = sd_bus_creds_get_uid(creds, &sender_uid); if (r >= 0) { /* Sender has same UID as us, then let's grant access */ if (sender_uid == our_uid) return 1; /* Sender is root, we are not root. */ if (our_uid != 0 && sender_uid == 0) return 1; } } return 0; }
/* Any time an access gets denied this callback will be called with the aduit data. We then need to just copy the audit data into the msgbuf. */ static int audit_callback( void *auditdata, security_class_t cls, char *msgbuf, size_t msgbufsize) { const struct audit_info *audit = auditdata; uid_t uid = 0, login_uid = 0; gid_t gid = 0; sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid); sd_bus_creds_get_uid(audit->creds, &uid); sd_bus_creds_get_gid(audit->creds, &gid); snprintf(msgbuf, msgbufsize, "auid=%d uid=%d gid=%d%s%s%s%s%s%s", login_uid, uid, gid, audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "", audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : ""); msgbuf[msgbufsize-1] = 0; return 0; }
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; uid_t our_uid; bool know_caps = false; int r; assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); assert_return(call->bus, -EINVAL); assert_return(!bus_pid_changed(call->bus), -ECHILD); if (!BUS_IS_OPEN(call->bus->state)) return -ENOTCONN; if (capability >= 0) { r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds); if (r < 0) return r; /* We cannot use augmented caps for authorization, * since then data is acquired raceful from * /proc. This can never actually happen, but let's * better be safe than sorry, and do an extra check * here. */ assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM); r = sd_bus_creds_has_effective_cap(creds, capability); if (r > 0) return 1; if (r == 0) know_caps = true; } else { r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds); if (r < 0) return r; } /* Now, check the UID, but only if the capability check wasn't * sufficient */ our_uid = getuid(); if (our_uid != 0 || !know_caps || capability < 0) { uid_t sender_uid; /* We cannot use augmented uid/euid for authorization, * since then data is acquired raceful from * /proc. This can never actually happen, but let's * better be safe than sorry, and do an extra check * here. */ assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM); /* Try to use the EUID, if we have it. */ r = sd_bus_creds_get_euid(creds, &sender_uid); if (r < 0) r = sd_bus_creds_get_uid(creds, &sender_uid); if (r >= 0) { /* Sender has same UID as us, then let's grant access */ if (sender_uid == our_uid) return 1; /* Sender is root, we are not root. */ if (our_uid != 0 && sender_uid == 0) return 1; } } return 0; }
int bus_verify_polkit_async( sd_bus *bus, Hashmap **registry, sd_bus_message *m, const char *action, bool interactive, sd_bus_error *error, sd_bus_message_handler_t callback, void *userdata) { #ifdef ENABLE_POLKIT _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; AsyncPolkitQuery *q; const char *sender; #endif _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t uid; int r; assert(bus); assert(registry); assert(m); assert(action); #ifdef ENABLE_POLKIT q = hashmap_get(*registry, m); if (q) { int authorized, challenge; /* This is the second invocation of this function, and * there's already a response from polkit, let's * process it */ assert(q->reply); if (sd_bus_message_is_method_error(q->reply, NULL)) { const sd_bus_error *e; /* Copy error from polkit reply */ e = sd_bus_message_get_error(q->reply); sd_bus_error_copy(error, e); /* Treat no PK available as access denied */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) return -EACCES; return sd_bus_error_get_errno(e); } r = sd_bus_message_enter_container(q->reply, 'r', "bba{ss}"); if (r >= 0) r = sd_bus_message_read(q->reply, "bb", &authorized, &challenge); if (r < 0) return r; if (authorized) return 1; return -EACCES; } #endif r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); if (r < 0) return r; r = sd_bus_creds_get_uid(creds, &uid); if (r < 0) return r; if (uid == 0) return 1; #ifdef ENABLE_POLKIT sender = sd_bus_message_get_sender(m); if (!sender) return -EBADMSG; r = hashmap_ensure_allocated(registry, trivial_hash_func, trivial_compare_func); if (r < 0) return r; r = sd_bus_message_new_method_call( bus, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", "CheckAuthorization", &pk); if (r < 0) return r; r = sd_bus_message_append( pk, "(sa{sv})sa{ss}us", "system-bus-name", 1, "name", "s", sender, action, 0, interactive ? 1 : 0, NULL); if (r < 0) return r; q = new0(AsyncPolkitQuery, 1); if (!q) return -ENOMEM; q->request = sd_bus_message_ref(m); q->callback = callback; q->userdata = userdata; r = hashmap_put(*registry, m, q); if (r < 0) { async_polkit_query_free(bus, q); return r; } q->registry = *registry; r = sd_bus_call_async(bus, pk, async_polkit_callback, q, 0, &q->serial); if (r < 0) { async_polkit_query_free(bus, q); return r; } return 0; #endif return -EACCES; }
int bus_verify_polkit( sd_bus *bus, sd_bus_message *m, const char *action, bool interactive, bool *_challenge, sd_bus_error *e) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; uid_t uid; int r; assert(bus); assert(m); assert(action); r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_UID, &creds); if (r < 0) return r; r = sd_bus_creds_get_uid(creds, &uid); if (r < 0) return r; if (uid == 0) return 1; #ifdef ENABLE_POLKIT else { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; int authorized = false, challenge = false; const char *sender; sender = sd_bus_message_get_sender(m); if (!sender) return -EBADMSG; r = sd_bus_call_method( bus, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", "CheckAuthorization", e, &reply, "(sa{sv})sa{ss}us", "system-bus-name", 1, "name", "s", sender, action, 0, interactive ? 1 : 0, ""); if (r < 0) { /* Treat no PK available as access denied */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN)) { sd_bus_error_free(e); return -EACCES; } return r; } r = sd_bus_message_enter_container(reply, 'r', "bba{ss}"); if (r >= 0) r = sd_bus_message_read(reply, "bb", &authorized, &challenge); if (authorized) return 1; if (_challenge) { *_challenge = challenge; return 0; } } #endif return -EACCES; }