int cg_controller_from_attr(const char *attr, char **controller) { const char *dot; char *c; assert(attr); assert(controller); if (!filename_is_safe(attr)) return -EINVAL; dot = strchr(attr, '.'); if (!dot) { *controller = NULL; return 0; } c = strndup(attr, dot - attr); if (!c) return -ENOMEM; if (!filename_is_safe(c)) { free(c); return -EINVAL; } *controller = c; return 1; }
static bool valid_machine_name(const char *p) { size_t l; if (!filename_is_safe(p)) return false; if (!ascii_is_valid(p)) return false; l = strlen(p); if (l < 1 || l> 64) return false; return true; }
int cg_split_spec(const char *spec, char **controller, char **path) { const char *e; char *t = NULL, *u = NULL; assert(spec); if (*spec == '/') { if (!path_is_safe(spec)) return -EINVAL; if (path) { t = strdup(spec); if (!t) return -ENOMEM; *path = t; } if (controller) *controller = NULL; return 0; } e = strchr(spec, ':'); if (!e) { if (!filename_is_safe(spec)) return -EINVAL; if (controller) { t = strdup(spec); if (!t) return -ENOMEM; *controller = t; } if (path) *path = NULL; return 0; } t = strndup(spec, e-spec); if (!t) return -ENOMEM; if (!filename_is_safe(t)) { free(t); return -EINVAL; } u = strdup(e+1); if (!u) { free(t); return -ENOMEM; } if (!path_is_safe(u)) { free(t); free(u); return -EINVAL; } if (controller) *controller = t; else free(t); if (path) *path = u; else free(u); return 0; }
static int set_machine_info(Context *c, sd_bus *bus, 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(bus); 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", interactive, &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)) { free(c->data[prop]); c->data[prop] = NULL; } 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_safe(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("Failed to write machine info: %s", strerror(-r)); 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])); sd_bus_emit_properties_changed(bus, "/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); }