static int get_creds(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; const char *name; int r; assert(bus); assert(m); assert(_creds); r = sd_bus_message_read(m, "s", &name); if (r < 0) return r; assert_return(service_name_is_valid(name), -EINVAL); r = sd_bus_get_owner(bus, name, mask, &c); if (r == -ENOENT || r == -ENXIO) return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name); if (r < 0) return r; if ((c->mask & mask) != mask) return -ENOTSUP; *_creds = c; c = NULL; return 0; }
_public_ int sd_bus_match_signal_async( sd_bus *bus, sd_bus_slot **ret, const char *sender, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, sd_bus_message_handler_t install_callback, void *userdata) { const char *expression; assert_return(bus, -EINVAL); assert_return(bus = bus_resolve(bus), -ENOPKG); assert_return(!bus_pid_changed(bus), -ECHILD); assert_return(!sender || service_name_is_valid(sender), -EINVAL); assert_return(!path || object_path_is_valid(path), -EINVAL); assert_return(!interface || interface_name_is_valid(interface), -EINVAL); assert_return(!member || member_name_is_valid(member), -EINVAL); expression = make_expression(sender, path, interface, member); return sd_bus_add_match_async(bus, ret, expression, callback, install_callback, userdata); }
_public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; _cleanup_free_ char *n = NULL; const char *match; int r; assert_return(track, -EINVAL); assert_return(service_name_is_valid(name), -EINVAL); r = hashmap_ensure_allocated(&track->names, &string_hash_ops); if (r < 0) return r; n = strdup(name); if (!n) return -ENOMEM; /* First, subscribe to this name */ match = MATCH_FOR_NAME(n); r = sd_bus_add_match(track->bus, &slot, match, on_name_owner_changed, track); if (r < 0) return r; r = hashmap_put(track->names, n, slot); if (r == -EEXIST) return 0; if (r < 0) return r; /* Second, check if it is currently existing, or maybe * doesn't, or maybe disappeared already. */ r = sd_bus_get_name_creds(track->bus, n, 0, NULL); if (r < 0) { hashmap_remove(track->names, n); return r; } n = NULL; slot = NULL; bus_track_remove_from_queue(track); track->modified = true; return 1; }
static int busname_verify(BusName *n) { char *e; assert(n); if (UNIT(n)->load_state != UNIT_LOADED) return 0; if (!service_name_is_valid(n->name)) { log_unit_error(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id); return -EINVAL; } e = strjoina(n->name, ".busname"); if (!unit_has_name(UNIT(n), e)) { log_unit_error(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id); return -EINVAL; } return 0; }
static int driver_list_queued_owners(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { struct kdbus_cmd_name_list cmd = {}; struct kdbus_name_list *name_list; struct kdbus_cmd_name *name; _cleanup_strv_free_ char **owners = NULL; char *arg0; int r; r = sd_bus_message_read(m, "s", &arg0); if (r < 0) return r; assert_return(service_name_is_valid(arg0), -EINVAL); cmd.flags = KDBUS_NAME_LIST_QUEUED; r = ioctl(bus->input_fd, KDBUS_CMD_NAME_LIST, &cmd); if (r < 0) return -errno; name_list = (struct kdbus_name_list *) ((uint8_t *) bus->kdbus_buffer + cmd.offset); KDBUS_ITEM_FOREACH(name, name_list, names) { char *n; if (name->size <= sizeof(*name)) continue; if (!streq(name->name, arg0)) continue; if (asprintf(&n, ":1.%llu", (unsigned long long) name->owner_id) < 0) return -ENOMEM; r = strv_push(&owners, n); if (r < 0) { free(n); return -ENOMEM; } }
static int add_dbus(const char *path, const char *fname, const char *type) { _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL; const ConfigTableItem table[] = { { "D-BUS Service", "Name", config_parse_string, 0, &name }, { "D-BUS Service", "Exec", config_parse_string, 0, &exec }, { "D-BUS Service", "User", config_parse_string, 0, &user }, { "D-BUS Service", "SystemdService", config_parse_string, 0, &service }, { }, }; char *p; int r; assert(path); assert(fname); p = strjoina(path, "/", fname); r = config_parse(NULL, p, NULL, "D-BUS Service\0", config_item_table_lookup, table, true, false, true, NULL); if (r < 0) return r; if (!name) { log_warning("Activation file %s lacks name setting, ignoring.", p); return 0; } if (!service_name_is_valid(name)) { log_warning("Bus service name %s is not valid, ignoring.", name); return 0; } if (streq(name, "org.freedesktop.systemd1")) { log_debug("Skipping %s, identified as systemd.", p); return 0; } if (service) { if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { log_warning("Unit name %s is not valid, ignoring.", service); return 0; } if (!endswith(service, ".service")) { log_warning("Bus names can only activate services, ignoring %s.", p); return 0; } } else { if (streq(exec, "/bin/false") || !exec) { log_warning("Neither service name nor binary path specified, ignoring %s.", p); return 0; } if (exec[0] != '/') { log_warning("Exec= in %s does not start with an absolute path, ignoring.", p); return 0; } } return create_dbus_files(p, name, service, exec, user, type); }
static int add_dbus(const char *path, const char *fname, const char *type) { _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL; ConfigTableItem table[] = { { "D-BUS Service", "Name", config_parse_string, 0, &name }, { "D-BUS Service", "Exec", config_parse_string, 0, &exec }, { "D-BUS Service", "User", config_parse_string, 0, &user }, { "D-BUS Service", "SystemdService", config_parse_string, 0, &service }, }; _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; int r; assert(path); assert(fname); p = strjoin(path, "/", fname, NULL); if (!p) return log_oom(); f = fopen(p, "re"); if (!f) { if (errno == -ENOENT) return 0; log_error("Failed to read %s: %m", p); return -errno; } r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL); if (r < 0) return r; if (!name) { log_warning("Activation file %s lacks name setting, ignoring.", p); return 0; } if (!service_name_is_valid(name)) { log_warning("Bus service name %s is not valid, ignoring.", name); return 0; } if (streq(name, "org.freedesktop.systemd1")) { log_debug("Skipping %s, identified as systemd.", p); return 0; } if (service) { if (!unit_name_is_valid(service, TEMPLATE_INVALID)) { log_warning("Unit name %s is not valid, ignoring.", service); return 0; } if (!endswith(service, ".service")) { log_warning("Bus names can only activate services, ignoring %s.", p); return 0; } } else { if (streq(exec, "/bin/false") || !exec) { log_warning("Neither service name nor binary path specified, ignoring %s.", p); return 0; } if (exec[0] != '/') { log_warning("Exec= in %s does not start with an absolute path, ignoring.", p); return 0; } } return create_dbus_files(p, name, service, exec, user, type); }
r = sd_bus_message_read(message, "sss", &name, &old, &new); if (r < 0) return 0; bus_track_remove_name_fully(track, name); return 0; } _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { _cleanup_(track_item_freep) struct track_item *n = NULL; struct track_item *i; const char *match; int r; assert_return(track, -EINVAL); assert_return(service_name_is_valid(name), -EINVAL); i = hashmap_get(track->names, name); if (i) { if (track->recursive) { unsigned k = track->n_ref + 1; if (k < track->n_ref) /* Check for overflow */ return -EOVERFLOW; track->n_ref = k; } bus_track_remove_from_queue(track); return 0; }
static int bus_scope_set_transient_property( Scope *s, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error) { int r; assert(s); assert(name); assert(message); if (streq(name, "PIDs")) { unsigned n = 0; uint32_t pid; r = sd_bus_message_enter_container(message, 'a', "u"); if (r < 0) return r; while ((r = sd_bus_message_read(message, "u", &pid)) > 0) { if (pid <= 1) return -EINVAL; if (mode != UNIT_CHECK) { r = unit_watch_pid(UNIT(s), pid); if (r < 0 && r != -EEXIST) return r; } n++; } if (r < 0) return r; r = sd_bus_message_exit_container(message); if (r < 0) return r; if (n <= 0) return -EINVAL; return 1; } else if (streq(name, "Controller")) { const char *controller; char *c; r = sd_bus_message_read(message, "s", &controller); if (r < 0) return r; if (!isempty(controller) && !service_name_is_valid(controller)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller); if (mode != UNIT_CHECK) { if (isempty(controller)) c = NULL; else { c = strdup(controller); if (!c) return -ENOMEM; } free(s->controller); s->controller = c; } return 1; } else if (streq(name, "TimeoutStopUSec")) { if (mode != UNIT_CHECK) { r = sd_bus_message_read(message, "t", &s->timeout_stop_usec); if (r < 0) return r; unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec=%lluus\n", (unsigned long long) s->timeout_stop_usec); } else { r = sd_bus_message_skip(message, "t"); if (r < 0) return r; } return 1; } return 0; }
static int bus_scope_set_transient_property( Scope *s, const char *name, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error) { int r; assert(s); assert(name); assert(message); flags |= UNIT_PRIVATE; if (streq(name, "TimeoutStopUSec")) return bus_set_transient_usec(UNIT(s), name, &s->timeout_stop_usec, message, flags, error); if (streq(name, "PIDs")) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; unsigned n = 0; r = sd_bus_message_enter_container(message, 'a', "u"); if (r < 0) return r; for (;;) { uint32_t upid; pid_t pid; r = sd_bus_message_read(message, "u", &upid); if (r < 0) return r; if (r == 0) break; if (upid == 0) { if (!creds) { r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); if (r < 0) return r; } r = sd_bus_creds_get_pid(creds, &pid); if (r < 0) return r; } else pid = (uid_t) upid; r = unit_pid_attachable(UNIT(s), pid, error); if (r < 0) return r; if (!UNIT_WRITE_FLAGS_NOOP(flags)) { r = unit_watch_pid(UNIT(s), pid); if (r < 0 && r != -EEXIST) return r; } n++; } r = sd_bus_message_exit_container(message); if (r < 0) return r; if (n <= 0) return -EINVAL; return 1; } else if (streq(name, "Controller")) { const char *controller; /* We can't support direct connections with this, as direct connections know no service or unique name * concept, but the Controller field stores exactly that. */ if (sd_bus_message_get_bus(message) != UNIT(s)->manager->api_bus) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus."); r = sd_bus_message_read(message, "s", &controller); if (r < 0) return r; if (!isempty(controller) && !service_name_is_valid(controller)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller); if (!UNIT_WRITE_FLAGS_NOOP(flags)) { r = free_and_strdup(&s->controller, empty_to_null(controller)); if (r < 0) return r; } return 1; } return 0; }