int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) { Machine *m = userdata; int r; assert(message); assert(m); r = bus_verify_polkit_async( message, CAP_KILL, "org.freedesktop.machine1.manage-machines", NULL, false, UID_INVALID, &m->manager->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ r = machine_stop(m); if (r < 0) return r; return sd_bus_reply_method_return(message, NULL); }
int bus_image_method_remove( sd_bus_message *message, void *userdata, sd_bus_error *error) { Image *image = userdata; Manager *m = image->userdata; int r; assert(message); assert(image); r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ r = image_remove(image); if (r < 0) return r; return sd_bus_reply_method_return(message, NULL); }
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; const char *name; int interactive; char *h; int r; assert(m); assert(c); r = sd_bus_message_read(m, "sb", &name, &interactive); if (r < 0) return r; if (isempty(name)) name = c->data[PROP_STATIC_HOSTNAME]; if (isempty(name)) name = "localhost"; if (!hostname_is_valid(name, false)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name); if (streq_ptr(name, c->data[PROP_HOSTNAME])) return sd_bus_reply_method_return(m, NULL); r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-hostname", NULL, interactive, UID_INVALID, &c->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ h = strdup(name); if (!h) return -ENOMEM; free(c->data[PROP_HOSTNAME]); c->data[PROP_HOSTNAME] = h; r = context_update_kernel_hostname(c); if (r < 0) { log_error_errno(r, "Failed to set host name: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r)); } log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME])); (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL); return sd_bus_reply_method_return(m, NULL); }
static int bus_image_method_detach( sd_bus_message *message, void *userdata, sd_bus_error *error) { PortableChange *changes = NULL; Image *image = userdata; Manager *m = image->userdata; size_t n_changes = 0; int r, runtime; assert(message); assert(image); assert(m); r = sd_bus_message_read(message, "b", &runtime); if (r < 0) return r; r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, "org.freedesktop.portable1.attach-images", NULL, false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ r = portable_detach( sd_bus_message_get_bus(message), image->path, runtime ? PORTABLE_RUNTIME : 0, &changes, &n_changes, error); if (r < 0) goto finish; r = reply_portable_changes(message, changes, n_changes); finish: portable_changes_free(changes, n_changes); return r; }
int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) { Machine *m = userdata; const char *swho; int32_t signo; KillWho who; int r; assert(message); assert(m); r = sd_bus_message_read(message, "si", &swho, &signo); if (r < 0) return r; if (isempty(swho)) who = KILL_ALL; else { who = kill_who_from_string(swho); if (who < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho); } if (signo <= 0 || signo >= _NSIG) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo); r = bus_verify_polkit_async( message, CAP_KILL, "org.freedesktop.machine1.manage-machines", NULL, false, UID_INVALID, &m->manager->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ r = machine_kill(m, who, signo); if (r < 0) return r; return sd_bus_reply_method_return(message, NULL); }
int bus_image_method_rename( sd_bus_message *message, void *userdata, sd_bus_error *error) { Image *image = userdata; Manager *m = image->userdata; const char *new_name; int r; assert(message); assert(image); r = sd_bus_message_read(message, "s", &new_name); if (r < 0) return r; if (!image_name_is_valid(new_name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name); r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", NULL, false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ r = image_rename(image, new_name); if (r < 0) return r; return sd_bus_reply_method_return(message, NULL); }
static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Context *c = userdata; int interactive, r; assert(m); assert(c); if (!c->has_uuid) return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid"); r = sd_bus_message_read(m, "b", &interactive); if (r < 0) return r; r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.get-product-uuid", NULL, interactive, UID_INVALID, &c->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = sd_bus_message_new_method_return(m, &reply); if (r < 0) return r; r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid)); if (r < 0) return r; return sd_bus_send(NULL, reply, NULL); }
int bus_image_method_set_limit( sd_bus_message *message, void *userdata, sd_bus_error *error) { Image *image = userdata; Manager *m = image->userdata; uint64_t limit; int r; assert(message); r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; if (!FILE_SIZE_VALID_OR_INFINITY(limit)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range"); r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", NULL, false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ r = image_set_limit(image, limit); if (r < 0) return r; return sd_bus_reply_method_return(message, NULL); }
static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) { int interactive; const char *name; int r; assert(c); assert(m); r = sd_bus_message_read(m, "sb", &name, &interactive); if (r < 0) return r; if (isempty(name)) name = NULL; if (streq_ptr(name, c->data[prop])) return sd_bus_reply_method_return(m, NULL); /* Since the pretty hostname should always be changed at the * same time as the static one, use the same policy action for * both... */ r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info", NULL, interactive, UID_INVALID, &c->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ if (isempty(name)) { c->data[prop] = mfree(c->data[prop]); } else { char *h; /* The icon name might ultimately be used as file * name, so better be safe than sorry */ if (prop == PROP_ICON_NAME && !filename_is_valid(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name); if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name); if (prop == PROP_CHASSIS && !valid_chassis(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name); if (prop == PROP_DEPLOYMENT && !valid_deployment(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name); if (prop == PROP_LOCATION && string_has_cc(name, NULL)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name); h = strdup(name); if (!h) return -ENOMEM; free(c->data[prop]); c->data[prop] = h; } r = context_write_data_machine_info(c); if (r < 0) { log_error_errno(r, "Failed to write machine info: %m"); return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r)); } log_info("Changed %s to '%s'", prop == PROP_PRETTY_HOSTNAME ? "pretty host name" : prop == PROP_DEPLOYMENT ? "deployment" : prop == PROP_LOCATION ? "location" : prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop])); (void) sd_bus_emit_properties_changed( sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" : prop == PROP_DEPLOYMENT ? "Deployment" : prop == PROP_LOCATION ? "Location" : prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL); return sd_bus_reply_method_return(m, NULL); }
int bus_image_method_remove( sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; Image *image = userdata; Manager *m = image->userdata; pid_t child; int r; assert(message); assert(image); if (m->n_operations >= OPERATIONS_MAX) return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations."); r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, "org.freedesktop.machine1.manage-images", NULL, false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) return 1; /* Will call us back */ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m"); child = fork(); if (child < 0) return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); if (child == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); r = image_remove(image); if (r < 0) { (void) write(errno_pipe_fd[1], &r, sizeof(r)); _exit(EXIT_FAILURE); } _exit(EXIT_SUCCESS); } errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); r = operation_new(m, NULL, child, message, errno_pipe_fd[0]); if (r < 0) { (void) sigkill_wait(child); return r; } errno_pipe_fd[0] = -1; return 1; }
int bus_image_acquire( Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, ImageAcquireMode mode, const char *polkit_action, Image **ret, sd_bus_error *error) { _cleanup_(image_unrefp) Image *loaded = NULL; Image *cached; int r; assert(m); assert(message); assert(name_or_path || image); assert(mode >= 0); assert(mode < _BUS_IMAGE_ACQUIRE_MODE_MAX); assert(polkit_action || mode == BUS_IMAGE_REFUSE_BY_PATH); assert(ret); /* Acquires an 'Image' object if not acquired yet, and enforces necessary authentication while doing so. */ if (mode == BUS_IMAGE_AUTHENTICATE_ALL) { r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, polkit_action, NULL, false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) { /* Will call us back */ *ret = NULL; return 0; } } /* Already passed in? */ if (image) { *ret = image; return 1; } /* Let's see if this image is already cached? */ cached = manager_image_cache_get(m, name_or_path); if (cached) { *ret = cached; return 1; } if (image_name_is_valid(name_or_path)) { /* If it's a short name, let's search for it */ r = image_find(IMAGE_PORTABLE, name_or_path, &loaded); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path); /* other errors are handled below… */ } else { /* Don't accept path if this is always forbidden */ if (mode == BUS_IMAGE_REFUSE_BY_PATH) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Expected image name, not path in place of '%s'.", name_or_path); if (!path_is_absolute(name_or_path)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is not valid or not a valid path.", name_or_path); if (!path_is_normalized(name_or_path)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image path '%s' is not normalized.", name_or_path); if (mode == BUS_IMAGE_AUTHENTICATE_BY_PATH) { r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, polkit_action, NULL, false, UID_INVALID, &m->polkit_registry, error); if (r < 0) return r; if (r == 0) { /* Will call us back */ *ret = NULL; return 0; } } r = image_from_path(name_or_path, &loaded); } if (r == -EMEDIUMTYPE) { sd_bus_error_setf(error, BUS_ERROR_BAD_PORTABLE_IMAGE_TYPE, "Typ of image '%s' not recognized; supported image types are directories/btrfs subvolumes, block devices, and raw disk image files with suffix '.raw'.", name_or_path); return r; } if (r < 0) return r; /* Add what we just loaded to the cache. This has as side-effect that the object stays in memory until the * cache is purged again, i.e. at least for the current event loop iteration, which is all we need, and which * means we don't actually need to ref the return object. */ r = manager_image_cache_add(m, loaded); if (r < 0) return r; *ret = loaded; return 1; }