/* * Recover object state from an XML file */ static ni_bool_t ni_objectmodel_recover_object_state_xml(xml_node_t *object_node, ni_dbus_object_t *object, const char **prefix_list) { xml_node_t *prop_node; /* Now process all the different properties */ for (prop_node = object_node->children; prop_node; prop_node = prop_node->next) { ni_dbus_variant_t dict = NI_DBUS_VARIANT_INIT; const char *interface_name; const ni_dbus_service_t *service; dbus_bool_t rv; interface_name = prop_node->name; if (prefix_list) { ni_bool_t match = FALSE; unsigned int i; for (i = 0; prefix_list[i] && !match; ++i) { const char *pfx = prefix_list[i]; unsigned int len; len = strlen(pfx); match = !strncmp(pfx, interface_name, len) && (interface_name[len] == '.' || interface_name[len] == '\0'); } if (!match) continue; } /* Parse the XML properties and store in a dbus dict. */ if (ni_dbus_xml_serialize_properties(__ni_objectmodel_schema, &dict, prop_node) < 0) { ni_error("%s: unable to parse xml properties", xml_node_location(prop_node)); ni_dbus_variant_destroy(&dict); return FALSE; } /* If ni_dbus_xml_serialize_properties succeeded, the following call cannot fail. */ service = ni_objectmodel_service_by_name(interface_name); /* Now set the object properties from the dbus dict */ rv = ni_dbus_object_set_properties_from_dict(object, service, &dict, NULL); ni_dbus_variant_destroy(&dict); if (!rv) { ni_error("%s: unable to assign properties", xml_node_location(prop_node)); return FALSE; } } return TRUE; }
/* * Filesystem.getInfo(path) * */ static dbus_bool_t __ni_Testbus_Agent_Filesystem_getInfo(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_dbus_variant_t res = NI_DBUS_VARIANT_INIT; struct stat stb; const char *path; dbus_bool_t rv; if (argc != 1 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/') return ni_dbus_error_invalid_args(error, object->path, method->name); if (stat(path, &stb) < 0) { ni_dbus_set_error_from_errno(error, errno, "unable to stat file \"%s\"", path); return FALSE; } if (!S_ISREG(stb.st_mode)) { dbus_set_error(error, DBUS_ERROR_FAILED, "not a regular file"); return FALSE; } ni_dbus_variant_init_dict(&res); ni_dbus_dict_add_uint64(&res, "size", stb.st_size); rv = ni_dbus_message_serialize_variants(reply, 1, &res, error); ni_dbus_variant_destroy(&res); return rv; }
/* * Get the state of a dbus object as XML. * We do this by going via the dbus representation, which is a bit of a waste of * time but at least that saves me from writing lots of code, and it makes sure * that we have one canonical mapping. * In fact, this is a lot like doing a Properties.GetAll call... */ static ni_bool_t ni_objectmodel_save_object_state_xml(const ni_dbus_object_t *object, xml_node_t *parent) { const ni_dbus_service_t *service; xml_node_t *object_node; unsigned int i; int rv = TRUE; object_node = xml_node_new("object", parent); xml_node_add_attr(object_node, "path", object->path); for (i = 0; rv && (service = object->interfaces[i]) != NULL; ++i) { ni_dbus_variant_t dict = NI_DBUS_VARIANT_INIT; xml_node_t *prop_node; ni_dbus_variant_init_dict(&dict); rv = ni_dbus_object_get_properties_as_dict(object, service, &dict, NULL); if (rv && dict.array.len != 0) { /* serialize as XML */ prop_node = ni_dbus_xml_deserialize_properties(__ni_objectmodel_schema, service->name, &dict, object_node); if (!prop_node) rv = FALSE; } ni_dbus_variant_destroy(&dict); } return rv; }
/* * Filesystem.download(path, offset, count) * */ static dbus_bool_t __ni_Testbus_Agent_Filesystem_download(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_dbus_variant_t res = NI_DBUS_VARIANT_INIT; const char *path; uint64_t offset; uint32_t count; dbus_bool_t rv; ni_buffer_t *bp = NULL; int fd = -1; if (argc != 3 || !ni_dbus_variant_get_string(&argv[0], &path) || path[0] != '/' || !ni_dbus_variant_get_uint64(&argv[1], &offset) || !ni_dbus_variant_get_uint32(&argv[2], &count) || count > 1024 * 1024 || offset + count < offset) return ni_dbus_error_invalid_args(error, object->path, method->name); if ((fd = open(path, O_RDONLY)) < 0) { ni_dbus_set_error_from_errno(error, errno, "unable to open file \"%s\"", path); return FALSE; } if (lseek(fd, offset, SEEK_SET) < 0) { ni_dbus_set_error_from_errno(error, errno, "seek faile"); goto out_fail; } bp = ni_buffer_new(count); while (count) { int n; n = read(fd, ni_buffer_tail(bp), ni_buffer_tailroom(bp)); if (n < 0) { ni_dbus_set_error_from_errno(error, errno, "read failed"); goto out_fail; } if (n == 0) break; ni_buffer_push_tail(bp, n); } ni_dbus_variant_init_dict(&res); ni_dbus_variant_set_byte_array(&res, ni_buffer_head(bp), ni_buffer_count(bp)); rv = ni_dbus_message_serialize_variants(reply, 1, &res, error); ni_dbus_variant_destroy(&res); ni_buffer_free(bp); close(fd); return rv; out_fail: if (fd >= 0) close(fd); return FALSE; }
/* * Create client handle for addrconf forwarder */ static dbus_bool_t ni_objectmodel_addrconf_forwarder_call(ni_dbus_addrconf_forwarder_t *forwarder, ni_netdev_t *dev, const char *method_name, const ni_uuid_t *uuid, const ni_dbus_variant_t *dict, DBusError *error) { ni_dbus_object_t *object; char object_path[256]; ni_dbus_variant_t argv[2]; int argc = 0; dbus_bool_t rv; if (forwarder->supplicant.client == NULL) { forwarder->supplicant.client = ni_create_dbus_client(forwarder->supplicant.bus_name); if (forwarder->supplicant.client == NULL) { dbus_set_error(error, "unable to create call forwarder for %s", forwarder->supplicant.bus_name); return FALSE; } ni_dbus_client_add_signal_handler(forwarder->supplicant.client, forwarder->supplicant.bus_name, /* sender must be the supplicant */ NULL, /* any object */ NI_OBJECTMODEL_ADDRCONF_INTERFACE, /* interface */ ni_objectmodel_addrconf_signal_handler, forwarder); } /* Build the path of the object to talk to in the supplicant service */ snprintf(object_path, sizeof(object_path), "%s/%u", forwarder->supplicant.object_path, dev->link.ifindex); object = ni_dbus_client_object_new(forwarder->supplicant.client, &forwarder->class, object_path, forwarder->supplicant.interface, NULL); /* Build the arguments. Note that we don't clone the dict, we just assign it * to argv[1]. Thus, we must make sure we never call ni_dbus_variant_destroy on argv[1] */ memset(argv, 0, sizeof(argv)); ni_dbus_variant_set_uuid(&argv[argc++], uuid); if (dict) argv[argc++] = *dict; /* Call the supplicant's method */ rv = ni_dbus_object_call_variant(object, forwarder->supplicant.interface, method_name, argc, argv, 0, NULL, error); ni_dbus_object_free(object); ni_dbus_variant_destroy(&argv[0]); return rv; }
/* * Wickedd is sending us a signal indicating internal device state change. * We want to wait for this signal and when it is >= device-up return TRUE. * After timeout we fail... */ void ni_state_change_signal_handler(ni_dbus_connection_t *conn, ni_dbus_message_t *msg, void *user_data) { const char *signal_name = dbus_message_get_member(msg); const char *object_path = dbus_message_get_path(msg); ni_dbus_variant_t argv = NI_DBUS_VARIANT_INIT; ni_ifworker_array_t *ifworkers = user_data; ni_fsm_state_t cur_state, target_state; const char *ifname; unsigned int i; if (ni_string_empty(object_path)) return; /* Deserialize dbus message */ if (ni_dbus_message_get_args_variants(msg, &argv, 1) < 0 || !ni_dbus_variant_is_dict(&argv)) { ni_error("Unable to retrieve dict from signal %s, object_path=%s", signal_name, object_path); return; } if (!ni_dbus_dict_get_uint32(&argv, "current-state", &cur_state) || !ni_dbus_dict_get_uint32(&argv, "target-state", &target_state) || !ni_dbus_dict_get_string(&argv, "ifname", &ifname)) { ni_error("Unable to retrieve dict's values from signal %s, object_path=%s", signal_name, object_path); return; } ni_debug_application("received signal %s; object_path=%s; target_state=%s, state_name=%s", signal_name, object_path, ni_ifworker_state_name(target_state), ni_ifworker_state_name(cur_state)); for (i = 0; i < ifworkers->count; ++i) { ni_ifworker_t *w = ifworkers->data[i]; if (cur_state != NI_FSM_STATE_NONE && cur_state != target_state) continue; if (!ni_string_eq(w->name, ifname)) continue; ni_warn("%s: Device %s", ifname, cur_state == target_state ? "succeeded" : "failed"); ni_ifworker_array_remove_with_children(ifworkers, w); } ni_dbus_variant_destroy(&argv); }
/* * Identify an interface by name */ char * ni_call_device_by_name(ni_dbus_object_t *list_object, const char *name) { DBusError error = DBUS_ERROR_INIT; ni_dbus_variant_t arg = NI_DBUS_VARIANT_INIT; ni_dbus_variant_t res = NI_DBUS_VARIANT_INIT; char *result = NULL; ni_dbus_variant_set_string(&arg, name); if (ni_dbus_object_call_variant(list_object, NULL, "deviceByName", 1, &arg, 1, &res, &error)) { const char *value; if (ni_dbus_variant_get_string(&res, &value)) result = strdup(value); } else { ni_dbus_print_error(&error, "%s.deviceByName(%s): failed", list_object->path, name); dbus_error_free(&error); } ni_dbus_variant_destroy(&arg); ni_dbus_variant_destroy(&res); return result; }
/* * Send Eventlog.connected() signal */ static void ni_testbus_eventlog_signal_eventsAdded(ni_dbus_object_t *eventlog_object, uint32_t last_seq) { ni_dbus_variant_t arg = NI_DBUS_VARIANT_INIT; ni_dbus_variant_set_uint32(&arg, last_seq); /* Send the signal */ ni_dbus_server_send_signal(ni_dbus_object_get_server(eventlog_object), eventlog_object, NI_TESTBUS_EVENTLOG_INTERFACE, "eventsAdded", 1, &arg); ni_dbus_variant_destroy(&arg); }
/* * Callback from addrconf supplicant whenever it acquired, released or lost a lease. * * FIXME SECURITY: * Is it good enough to check for the sender interface to avoid that someone is sending * us spoofed lease messages?! */ void ni_objectmodel_addrconf_signal_handler(ni_dbus_connection_t *conn, ni_dbus_message_t *msg, void *user_data) { ni_dbus_addrconf_forwarder_t *forwarder = user_data; const char *signal_name = dbus_message_get_member(msg); ni_netdev_t *ifp; ni_addrconf_lease_t *lease = NULL; ni_dbus_variant_t argv[16]; ni_uuid_t uuid = NI_UUID_INIT; ni_event_t ifevent; int argc, optind = 0; memset(argv, 0, sizeof(argv)); argc = ni_dbus_message_get_args_variants(msg, argv, 16); if (argc < 0) { ni_error("%s: cannot parse arguments for signal %s", __func__, signal_name); goto done; } ifp = ni_objectmodel_addrconf_path_to_device(dbus_message_get_path(msg)); if (ifp == NULL) { ni_debug_dbus("%s: received signal %s for unknown interface %s", __func__, signal_name, dbus_message_get_path(msg)); goto done; } lease = ni_addrconf_lease_new(forwarder->addrconf, forwarder->addrfamily); if (argc != 1 && argc != 2) { ni_warn("%s: ignoring %s event from %s: bad number of arguments (%u)", __func__, signal_name, dbus_message_get_path(msg), argc); goto done; } if (argc == 2 && !ni_dbus_variant_get_uuid(&argv[optind++], &uuid)) { ni_debug_dbus("%s: unable to parse uuid argument", __func__); goto done; } if (!ni_objectmodel_set_addrconf_lease(lease, &argv[optind++])) { ni_error("%s: unable to parse lease argument received from %s", __func__, dbus_message_get_sender(msg)); goto done; } ni_debug_dbus("received signal %s for interface %s (ifindex %d), lease %s:%s, uuid=%s, update=0x%x, flags=0x%x", signal_name, ifp->name, ifp->link.ifindex, ni_addrfamily_type_to_name(lease->family), ni_addrconf_type_to_name(lease->type), ni_uuid_print(&uuid), lease->update, lease->flags); if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_ACQUIRED_SIGNAL)) { if (lease->state != NI_ADDRCONF_STATE_GRANTED) { ni_error("%s: unexpected lease state in signal %s", __func__, signal_name); goto done; } ifevent = NI_EVENT_ADDRESS_ACQUIRED; if (!__ni_addrconf_should_update(lease->update, NI_ADDRCONF_UPDATE_DEFAULT_ROUTE)) { ni_route_table_t *tab; ni_route_t *rp; unsigned int i; for (tab = lease->routes; tab; tab = tab->next) { for (i = 0; i < tab->routes.count; ++i) { if (!(rp = tab->routes.data[i])) continue; if (ni_sockaddr_is_specified(&rp->destination)) continue; if (ni_route_array_delete(&tab->routes, i)) i--; } } } } else if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_RELEASED_SIGNAL)) { lease->state = NI_ADDRCONF_STATE_RELEASED; ifevent = NI_EVENT_ADDRESS_RELEASED; } else if (!strcmp(signal_name, NI_OBJECTMODEL_LEASE_LOST_SIGNAL)) { lease->state = NI_ADDRCONF_STATE_FAILED; ifevent = NI_EVENT_ADDRESS_LOST; } else { /* Ignore unknown signal */ goto done; } /* * The following call updates the system with the information given in * the lease. This includes setting all addresses, as well as updating * resolver and hostname, if provided. * When a lease is dropped, we either fall back to the config information * from the next best lease, or if there is none, we restore the original * system settings. * * Note, lease may be NULL after this, as the interface object * takes ownership of it. */ __ni_system_interface_update_lease(ifp, &lease); /* Potentially, there's a client somewhere waiting for that event. * We use the UUID that's passed back and forth to make sure we * really match the event we were expecting to match. */ { ni_dbus_object_t *object; object = ni_objectmodel_get_netif_object(__ni_objectmodel_server, ifp); if (object) ni_objectmodel_send_netif_event(__ni_objectmodel_server, object, ifevent, ni_uuid_is_null(&uuid)? NULL : &uuid); } done: while (argc--) ni_dbus_variant_destroy(&argv[argc]); if (lease) ni_addrconf_lease_free(lease); }