ni_bool_t ni_netdev_alias_label_is_valid(const char *ifname, const char *alabel) { size_t nlen = ni_string_len(ifname); size_t alen = ni_string_len(alabel); /* assume ifname is verified already/separately */ if (!nlen || !alen || alen >= IFNAMSIZ) return FALSE; if (!strncmp(ifname, alabel, nlen)) { /* alabel is equal to ifname/no label */ if (alen == nlen) return TRUE; /* alabel contains "<ifname>:" prefix */ return __ni_netdev_alias_label_is_valid(alabel + nlen) > 0; } else if (alen + nlen + 1 < IFNAMSIZ) { /* alabel without "<ifname>:" prefix */ return __ni_netdev_alias_label_is_valid(alabel) > 0; } else { /* "<ifname>:<alabel>" is too long */ return FALSE; } }
static int ni_do_duid_create(int argc, char **argv) { enum { OPT_HELP = 'h' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; const char *type = NULL; char *command = NULL; optind = 1; while ((opt = getopt_long(argc, argv, "+h", options, NULL)) != EOF) { switch (opt) { case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options] <ll|llt|en|uuid> ...\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" "\n", argv[0]); goto cleanup; } } if (optind >= argc || ni_string_empty(argv[optind])) { fprintf(stderr, "%s: missing duid type argument\n\n", argv[0]); goto usage; } type = argv[optind]; ni_string_printf(&command, "%s %s", argv[0], type); argv[optind] = command; if (ni_string_eq(type, "ll")) { status = ni_do_duid_create_ll(argc - optind, argv + optind); } else if (ni_string_eq(type, "llt")) { status = ni_do_duid_create_llt(argc - optind, argv + optind); } else if (ni_string_eq(type, "en")) { status = ni_do_duid_create_en(argc - optind, argv + optind); } else if (ni_string_eq(type, "uuid")) { status = ni_do_duid_create_uuid(argc - optind, argv + optind); } else { argv[optind] = (char *)type; fprintf(stderr, "%s: unsupported duid type '%s'\n", argv[0], ni_print_suspect(type, ni_string_len(type))); goto usage; } argv[optind] = (char *)type; cleanup: ni_string_free(&command); return status; }
ni_bool_t ni_wireless_parse_ssid(const char *string, ni_wireless_ssid_t *ssid) { const char *s = string; const char *e; int ret; if (!string || !ssid) goto bad_ssid; e = s + ni_string_len(s); memset(ssid, 0, sizeof(*ssid)); while (e > s) { unsigned char cc = *s++; if (cc == '\\') { ret = __ni_wireless_parse_ssid_esc(&cc, s, e); if (ret < 0) goto bad_ssid; s += ret; } ret = __ni_wireless_parse_ssid_put(ssid, cc); if (ret < 0) goto bad_ssid; } return TRUE; bad_ssid: ni_debug_wireless("unable to parse wireless ssid \"%s\"", string); return FALSE; }
ni_bool_t ni_iaid_map_save(ni_iaid_map_t *map) { char *data = NULL; size_t off, len; ssize_t ret; if (!map || map->fd < 0) return FALSE; if (lseek(map->fd, 0, SEEK_SET) < 0) return FALSE; if (ftruncate(map->fd, 0) < 0) return FALSE; if (map->doc && map->doc->root) data = xml_node_sprint(map->doc->root); len = ni_string_len(data); off = 0; ret = 0; while (len > off) { ret = write(map->fd, data + off, len - off); if (ret < 0 && errno != EINTR) break; else if (ret > 0) off += ret; } free(data); return ret < 0 ? FALSE : TRUE; }
ni_bool_t ni_log_destination(const char *progname, const char *destination) { static const struct { const char *name; ni_bool_t (*func)(const char *, const char *); } *dest, destination_map[] = { { "stderr", ni_log_destination_stderr }, { "syslog", ni_log_destination_syslog }, { NULL, NULL } }; const char *options = ""; size_t len; if (!destination) return FALSE; /* * stderr[:[options]] * syslog[:[facility]:[options]] */ len = strcspn(destination, ":"); if (destination[len] == ':') { options = destination + len + 1; } for (dest = destination_map; dest->name; ++dest) { if (ni_string_len(dest->name) == len && !strncasecmp(dest->name, destination, len)) return dest->func(progname, options); } return FALSE; }
static void ni_json_string_escape(ni_stringbuf_t *buf, const char *str, const ni_json_format_options_t *options) { static const char *hex = "0123456789abcdefABCDEF"; size_t len = ni_string_len(str); size_t pos = 0, off = 0; unsigned char uc; const char *es; while (len--) { uc = str[pos]; es = ni_json_string_escape_map(uc, options); if (es) { if (pos - off > 0) ni_stringbuf_put(buf, str + off, pos - off); ni_stringbuf_puts(buf, es); off = ++pos; } else if (uc < ' ') { if (pos - off > 0) ni_stringbuf_put(buf, str + off, pos - off); ni_stringbuf_printf(buf, "\\u00%c%c", hex[uc >> 4], hex[uc & 0x0f]); off = ++pos; } else { pos++; } }
static int ni_do_duid_del(int argc, char **argv) { enum { OPT_HELP = 'h', OPT_SCOPE = 's' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "scope", required_argument, NULL, OPT_SCOPE }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; ni_duid_map_t *map = NULL; const char *scope = NULL; optind = 1; while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) { switch (opt) { case OPT_SCOPE: if (optarg && !ni_string_eq(optarg, "default")) scope = optarg; break; case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options]\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" " --scope <ifname> delete device specific duid instead of default\n" "\n", argv[0]); goto cleanup; } } if (argc - optind) goto usage; if (scope && !ni_netdev_name_is_valid(scope)) { fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], ni_print_suspect(scope, ni_string_len(scope))); status = NI_WICKED_RC_ERROR; goto cleanup; } status = NI_WICKED_RC_ERROR; if (!(map = ni_duid_map_load(NULL))) goto cleanup; if (ni_duid_map_del(map, scope)) { if (ni_duid_map_save(map)) status = NI_WICKED_RC_SUCCESS; } cleanup: ni_duid_map_free(map); return status; }
static dbus_bool_t ni_objectmodel_ethtool_set_priv_flags(ni_dbus_object_t *object, const ni_dbus_property_t *property, const ni_dbus_variant_t *argument, DBusError *error) { const ni_dbus_variant_t *dict; ni_ethtool_t *ethtool; unsigned int i, len; dbus_bool_t enabled; ni_stringbuf_t buf; const char *name; if (!ni_dbus_variant_is_dict_array(argument)) return FALSE; if (!(ethtool = ni_objectmodel_ethtool_write_handle(object, error))) return FALSE; ni_ethtool_priv_flags_free(ethtool->priv_flags); if (!(ethtool->priv_flags = ni_ethtool_priv_flags_new())) return FALSE; if ((len = argument->array.len) > 32) len = 32; ni_stringbuf_init(&buf); for (i = 0; i < argument->array.len; ++i) { dict = &argument->variant_array_value[i]; if (!ni_dbus_variant_is_dict(dict)) continue; if (!ni_dbus_dict_get_string(dict, "name", &name) || !ni_dbus_dict_get_bool(dict, "enabled", &enabled)) continue; ni_stringbuf_put(&buf, name, ni_string_len(name)); ni_stringbuf_trim_head(&buf, " \t\n"); ni_stringbuf_trim_tail(&buf, " \t\n"); if (ni_string_empty(buf.string)) continue; if (ni_string_array_append(ðtool->priv_flags->names, buf.string) == 0) { if (enabled) ethtool->priv_flags->bitmap |= NI_BIT(i); } ni_stringbuf_destroy(&buf); } return TRUE; }
unsigned int ni_string_split(ni_string_array_t *nsa, const char *str, const char *sep, unsigned int limit) { unsigned int count; char *tmp, *s, *p = NULL; if (nsa == NULL || ni_string_len(sep) == 0 || ni_string_len(str) == 0) return 0; if ((tmp = strdup(str)) == NULL) return 0; count = nsa->count; for (s = strtok_r(tmp, sep, &p); s; s = strtok_r(NULL, sep, &p)) { if (limit && (nsa->count - count) >= limit) break; ni_string_array_append(nsa, s); } free(tmp); return nsa->count - count; }
static size_t __ni_netdev_name_is_valid(const char *ifname) { size_t i, len = ni_string_len(ifname); if (!len || len >= IFNAMSIZ) return 0; for(i = 0; i < len; ++i) { if(isalnum((unsigned char)ifname[i]) || ifname[i] == '-' || ifname[i] == '_' || ifname[i] == '.') continue; return 0; } return len; }
void ni_wireless_blob_free(ni_wireless_blob_t *blob) { if (blob) { memset(blob->name, 0, ni_string_len(blob->name)); ni_string_free(&blob->name); if (blob->data) { memset(blob->data, 0, blob->size); free(blob->data); blob->data = NULL; blob->size = 0; } free(blob); blob = NULL; } }
static size_t __ni_netdev_alias_label_is_valid(const char *alabel) { size_t i, len = ni_string_len(alabel); if (!len || len >= IFNAMSIZ) return 0; for(i = 0; i < len; ++i) { if(isalnum((unsigned char)alabel[i]) || alabel[i] == '-' || alabel[i] == '_' || alabel[i] == '.' || alabel[i] == ':') continue; return 0; } return len; }
/* * This specifies sources of client configuration. * * The ifconfig source specifies the type, location and the * priority / load order of the interface configurations. * * <sources> * <ifconfig location="firmware:" /> * <ifconfig location="compat:" /> * <ifconfig location="wicked:/etc/wicked/ifconfig" /> * </sources> * */ static ni_bool_t __ni_config_parse_ifconfig_source(ni_string_array_t *sources, xml_node_t *node) { const char *attrval = NULL; unsigned int i; if ((attrval = xml_node_get_attr(node, "location")) != NULL && *attrval) { const char **p = __ni_ifconfig_source_types; for (i = 0; p[i]; i++) { if (!strncasecmp(attrval, p[i], ni_string_len(p[i]))) { ni_debug_readwrite("%s: Adding ifconfig %s", __func__, attrval); ni_string_array_append(sources, attrval); return TRUE; } } } ni_error("Unknown ifconfig location: %s", attrval); return FALSE; }
static int ni_dhcp4_option_get_domain_list(ni_buffer_t *bp, ni_string_array_t *var, const char *what) { ni_string_array_t list = NI_STRING_ARRAY_INIT; unsigned int len, i; char *tmp = NULL; if (ni_dhcp4_option_get_string(bp, &tmp, &len) < 0) return -1; /* * Hack to accept "compatibility abuse" of dns domain name * option containing multiple domains instead to send them * using a dns-search option... */ if (!ni_string_split(&list, tmp, " ", 0)) { ni_warn("Discarded suspect %s: '%s'", what, ni_print_suspect(tmp, len)); free(tmp); return -1; } for (i = 0; i < list.count; ++i) { const char *dom = list.data[i]; if (!ni_check_domain_name(dom, ni_string_len(dom), 0)) { ni_warn("Discarded suspect %s: '%s'", what, ni_print_suspect(tmp, len)); ni_string_array_destroy(&list); free(tmp); return -1; } } if (list.count != 1) { ni_warn("Abuse of %s option to provide a list: '%s'", what, tmp); } free(tmp); ni_string_array_move(var, &list); return 0; }
/* * Process a request to reconfigure the device (ie rebind a lease, or discover * a new lease). */ int ni_dhcp4_acquire(ni_dhcp4_device_t *dev, const ni_dhcp4_request_t *info) { ni_dhcp4_config_t *config; const char *classid; size_t len; int rv; if ((rv = ni_dhcp4_device_refresh(dev)) < 0) return rv; config = xcalloc(1, sizeof(*config)); config->dry_run = info->dry_run; config->resend_timeout = NI_DHCP4_RESEND_TIMEOUT_INIT; config->request_timeout = info->acquire_timeout?: NI_DHCP4_REQUEST_TIMEOUT; config->initial_discovery_timeout = NI_DHCP4_DISCOVERY_TIMEOUT; config->uuid = info->uuid; config->flags = info->flags; config->update = info->update; config->route_priority = info->route_priority; config->start_delay = info->start_delay; config->recover_lease = info->recover_lease; config->release_lease = info->release_lease; config->max_lease_time = ni_dhcp4_config_max_lease_time(); if (config->max_lease_time == 0) config->max_lease_time = ~0U; if (info->lease_time && info->lease_time < config->max_lease_time) config->max_lease_time = info->lease_time; if ((len = ni_string_len(info->hostname)) > 0) { if (ni_check_domain_name(info->hostname, len, 0)) { strncpy(config->hostname, info->hostname, sizeof(config->hostname) - 1); } else { ni_debug_dhcp("Discarded request to use suspect hostname: '%s'", ni_print_suspect(info->hostname, len)); } } if (info->clientid) { ni_dhcp4_parse_client_id(&config->client_id, dev->system.hwaddr.type, info->clientid); } else { /* Set client ID from interface hwaddr */ ni_dhcp4_set_client_id(&config->client_id, &dev->system.hwaddr); } if ((classid = info->vendor_class) == NULL) classid = ni_dhcp4_config_vendor_class(); if (classid) strncpy(config->classid, classid, sizeof(config->classid) - 1); config->doflags = DHCP4_DO_DEFAULT; config->doflags |= ni_dhcp4_do_bits(info->update); if (ni_debug & NI_TRACE_DHCP) { ni_trace("Received request:"); ni_trace(" acquire-timeout %u", config->request_timeout); ni_trace(" lease-time %u", config->max_lease_time); ni_trace(" start-delay %u", config->start_delay); ni_trace(" hostname %s", config->hostname[0]? config->hostname : "<none>"); ni_trace(" vendor-class %s", config->classid[0]? config->classid : "<none>"); ni_trace(" client-id %s", ni_print_hex(config->client_id.data, config->client_id.len)); ni_trace(" uuid %s", ni_uuid_print(&config->uuid)); ni_trace(" update-flags %s", __ni_dhcp4_print_doflags(config->doflags)); ni_trace(" recover_lease %s", config->recover_lease ? "true" : "false"); ni_trace(" release_lease %s", config->release_lease ? "true" : "false"); } ni_dhcp4_device_set_config(dev, config); if (!dev->lease) ni_dhcp4_recover_lease(dev); if (dev->lease) { if (!ni_addrconf_lease_is_valid(dev->lease) || (config->client_id.len && !ni_opaque_eq(&config->client_id, &dev->lease->dhcp4.client_id))) { ni_debug_dhcp("%s: lease doesn't match request", dev->ifname); ni_dhcp4_device_drop_lease(dev); dev->notify = 1; } } ni_note("%s: Request to acquire DHCPv4 lease with UUID %s", dev->ifname, ni_uuid_print(&config->uuid)); if (ni_dhcp4_device_start(dev) < 0) return -1; return 1; }
static int __ni_dhcp4_build_msg_put_our_hostname(const ni_dhcp4_device_t *dev, ni_buffer_t *msgbuf) { const ni_dhcp4_config_t *options = dev->config; size_t len = ni_string_len(options->hostname); if (!len) return 1; /* skipped hint */ if (options->fqdn == FQDN_DISABLE) { char hname[64] = {'\0'}, *end; /* * Truncate the domain part if fqdn to avoid attempts * to update DNS with foo.bar + update-domain. */ strncat(hname, options->hostname, sizeof(hname)-1); if ((end = strchr(hname, '.'))) *end = '\0'; len = ni_string_len(hname); if (ni_check_domain_name(hname, len, 0)) { ni_dhcp4_option_puts(msgbuf, DHCP4_HOSTNAME, hname); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using hostname: %s", dev->ifname, hname); } else { ni_info("%s: not sending suspect hostname: '%s'", dev->ifname, ni_print_suspect(hname, len)); return 1; } } else if (ni_check_domain_name(options->hostname, len, 0)) { /* IETF DHC-FQDN option(81) * http://tools.ietf.org/html/rfc4702#section-2.1 * * Flags: 0000NEOS * S: 1 => Client requests Server to update * a RR in DNS as well as PTR * O: 1 => Server indicates to client that * DNS has been updated * E: 1 => Name data is DNS format * N: 1 => Client requests Server to not * update DNS */ ni_buffer_putc(msgbuf, DHCP4_FQDN); ni_buffer_putc(msgbuf, len + 3); ni_buffer_putc(msgbuf, options->fqdn & 0x9); ni_buffer_putc(msgbuf, 0); /* from server for PTR RR */ ni_buffer_putc(msgbuf, 0); /* from server for A RR if S=1 */ ni_buffer_put(msgbuf, options->hostname, len); ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_DHCP, "%s: using fqdn: %s", dev->ifname, options->hostname); } else { ni_info("%s: not sending suspect fqdn: '%s'", dev->ifname, ni_print_suspect(options->hostname, len)); return 1; } return 0; }
static int ni_do_duid_set(int argc, char **argv) { enum { OPT_HELP = 'h', OPT_SCOPE = 's' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "scope", required_argument, NULL, OPT_SCOPE }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; ni_duid_map_t *map = NULL; const char *scope = NULL; const char *duid = NULL; ni_opaque_t raw; optind = 1; while ((opt = getopt_long(argc, argv, "+hs:", options, NULL)) != EOF) { switch (opt) { case OPT_SCOPE: if (optarg && !ni_string_eq(optarg, "default")) scope = optarg; break; case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options] <duid>\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" " --scope <ifname> set device specific duid instead of default\n" "\n" "Arguments:\n" " duid duid string as colon-separated hex bytes\n" "\n", argv[0]); goto cleanup; } } switch (argc - optind) { case 1: duid = argv[optind++]; break; default: goto usage; } if (scope && !ni_netdev_name_is_valid(scope)) { fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], ni_print_suspect(scope, ni_string_len(scope))); status = NI_WICKED_RC_ERROR; goto cleanup; } if (ni_string_empty(duid) || !ni_duid_parse_hex(&raw, duid)) { fprintf(stderr, "%s: unable to parse duid hex string argument\n", argv[0]); status = NI_WICKED_RC_ERROR; goto cleanup; } status = NI_WICKED_RC_ERROR; if (!(map = ni_duid_map_load(NULL))) goto cleanup; if (!ni_duid_map_set(map, scope, duid)) goto cleanup; if (!ni_duid_map_save(map)) goto cleanup; status = NI_WICKED_RC_SUCCESS; cleanup: ni_duid_map_free(map); return status; }
static ni_bool_t ni_dhcp4_tester_req_xml_init(ni_dhcp4_request_t *req, xml_document_t *doc) { xml_node_t *xml, *child; const char *type; xml = xml_document_root(doc); if (xml && !xml->name && xml->children) xml = xml->children; if (!xml || !ni_string_eq(xml->name, "request")) { ni_error("Invalid dhcp4 request xml '%s'", xml ? xml_node_location(xml) : NULL); return FALSE; } type = xml_node_get_attr(xml, "type"); if (ni_string_eq(type, "offer")) { req->dry_run = NI_DHCP4_RUN_OFFER; } else if (ni_string_eq(type, "lease")) { req->dry_run = NI_DHCP4_RUN_LEASE; } for (child = xml->children; child; child = child->next) { if (ni_string_eq(child->name, "uuid")) { if (ni_uuid_parse(&req->uuid, child->cdata) != 0) goto failure; } else if (ni_string_eq(child->name, "acquire-timeout")) { if (ni_parse_uint(child->cdata, &req->acquire_timeout, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "hostname")) { if (!ni_check_domain_name(child->cdata, ni_string_len(child->cdata), 0)) goto failure; ni_string_dup(&req->hostname, child->cdata); } else if (ni_string_eq(child->name, "fqdn")) { const xml_node_t *ptr; for (ptr = child->children; ptr; ptr = ptr->next) { if (ni_string_eq(ptr->name, "enabled")) { ni_bool_t b; if (ni_parse_boolean(ptr->cdata, &b) == 0) ni_tristate_set(&req->fqdn.enabled, b); else if (ni_string_eq(ptr->cdata, "default")) req->fqdn.enabled = NI_TRISTATE_DEFAULT; else goto failure; } else if (ni_string_eq(ptr->name, "update")) { if (!ni_dhcp_fqdn_update_name_to_mode(ptr->cdata, &req->fqdn.update)) goto failure; } else if (ni_string_eq(ptr->name, "encode")) { if (ni_parse_boolean(ptr->cdata, &req->fqdn.encode) != 0) goto failure; } else if (ni_string_eq(ptr->name, "qualify")) { if (ni_parse_boolean(ptr->cdata, &req->fqdn.qualify) != 0) goto failure; } } } else if (ni_string_eq(child->name, "clientid")) { ni_opaque_t duid; if (ni_parse_hex(child->cdata, duid.data, sizeof(duid.data)) <= 0) goto failure; ni_string_dup(&req->clientid, child->cdata); } else if(ni_string_eq(child->name, "start-delay")) { if (ni_parse_uint(child->cdata, &req->start_delay, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "lease-time")) { if (ni_parse_uint(child->cdata, &req->lease_time, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "recover-lease")) { if (ni_parse_boolean(child->cdata, &req->recover_lease) != 0) goto failure; } else if (ni_string_eq(child->name, "release-lease")) { if (ni_parse_boolean(child->cdata, &req->release_lease) != 0) goto failure; } else if (ni_string_eq(child->name, "request-options")) { xml_node_t *opt; for (opt = child->children; opt; opt = opt->next) { if (ni_string_empty(opt->cdata)) continue; ni_string_array_append(&req->request_options, opt->cdata); } } } return TRUE; failure: if (child) { ni_error("Cannot parse dhcp4 request '%s': %s", child->name, xml_node_location(child)); } return FALSE; }
static int ni_do_duid_create_en(int argc, char **argv) { enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "scope", required_argument, NULL, OPT_SCOPE }, { "update", no_argument, NULL, OPT_UPDATE }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; const char *scope = NULL; ni_bool_t update = FALSE; const char *en = NULL; const char *id = NULL; const char *hex = NULL; ni_opaque_t raw; optind = 1; while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) { switch (opt) { case OPT_UPDATE: update = TRUE; break; case OPT_SCOPE: if (optarg && !ni_string_eq(optarg, "default")) scope = optarg; break; case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options] <enterprise-number> <machine-identifier>\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" " --scope <ifname> create device specific duid instead of default\n" " --update create a duid and update duid map file\n" "\n" "Arguments:\n" " enterprise-number IANA assigned 32bit enterprise number\n" " machine-identifier machine identifier as colon-separated hex bytes\n" "\n", argv[0]); goto cleanup; } } switch (argc - optind) { case 2: en = argv[optind++]; id = argv[optind++]; break; default: goto usage; } status = NI_WICKED_RC_ERROR; if (scope && !ni_netdev_name_is_valid(scope)) { fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], ni_print_suspect(scope, ni_string_len(scope))); goto cleanup; } if (!ni_duid_create_en(&raw, en, id)) { fprintf(stderr, "%s: cannot create duid using enterprise-number '%s' and identifier '%s'\n", argv[0], en, id); goto cleanup; } hex = raw.len ? ni_duid_print_hex(&raw) : NULL; if (ni_string_empty(hex)) { fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); goto cleanup; } if (update) { status = ni_do_duid_create_update(scope, hex); if (status != NI_WICKED_RC_SUCCESS) { fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); goto cleanup; } } printf("%s\t%s\n", scope ? scope : "default", hex); status = NI_WICKED_RC_SUCCESS; cleanup: return status; }
static int ni_do_duid_create_ll_type(uint16_t type, int argc, char **argv) { enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "scope", required_argument, NULL, OPT_SCOPE }, { "update", no_argument, NULL, OPT_UPDATE }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; const char *scope = NULL; ni_bool_t update = FALSE; const char *ifname = NULL; const char *hwtype = NULL; const char *hwaddr = NULL; const char *hex = NULL; ni_opaque_t raw; optind = 1; while ((opt = getopt_long(argc, argv, "+hs:u", options, NULL)) != EOF) { switch (opt) { case OPT_UPDATE: update = TRUE; break; case OPT_SCOPE: if (optarg && !ni_string_eq(optarg, "default")) scope = optarg; break; case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options] [ [ifname] | <hwtype> <hwaddr> ]\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" " --scope <ifname> create device specific duid instead of default\n" " --update create a duid and update duid map file\n" "\n" "Arguments:\n" " ifname get hardware type and address from interface\n" " htwype hardware type to use in the duid\n" " htaddr hardware address to use in the duid\n" "\n", argv[0]); ni_do_duid_create_ll_print_hwtypes(stderr); goto cleanup; } } switch (argc - optind) { case 2: hwtype = argv[optind++]; hwaddr = argv[optind++]; break; case 1: ifname = argv[optind++]; break; case 0: break; default: goto usage; } status = NI_WICKED_RC_ERROR; if (scope && !ni_netdev_name_is_valid(scope)) { fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], ni_print_suspect(scope, ni_string_len(scope))); goto cleanup; } if (hwtype || hwaddr) { switch (type) { case NI_DUID_TYPE_LL: if (ni_duid_create_ll(&raw, hwtype, hwaddr)) status = NI_WICKED_RC_SUCCESS; break; case NI_DUID_TYPE_LLT: if (ni_duid_create_llt(&raw, hwtype, hwaddr)) status = NI_WICKED_RC_SUCCESS; break; default: break; } if (status != NI_WICKED_RC_SUCCESS) { fprintf(stderr, "%s: cannot create duid using hardware type '%s' and address '%s'\n", argv[0], hwtype, hwaddr); goto cleanup; } } else { ni_netconfig_t *nc = ni_global_state_handle(1); ni_netdev_t *dev = NULL; if (!nc) { fprintf(stderr, "%s: cannot retrieve interface properties", argv[0]); goto cleanup; } if (ifname) { dev = ni_netdev_by_name(nc, ifname); if (!dev || !ni_duid_create_from_device(&raw, type, dev)) { hwtype = dev ? ni_duid_hwtype_to_name(dev->link.hwaddr.type) : "missing"; fprintf(stderr, "%s: unable to create %s duid using %s device '%s'\n", argv[0], ni_duid_type_to_name(type), hwtype ? hwtype : "unsupported", ifname); goto cleanup; } } else { dev = scope ? ni_netdev_by_name(nc, scope) : NULL; if (!ni_duid_create_pref_device(&raw, type, nc, dev)) { fprintf(stderr, "%s: unable to create any %s duid (no usable devices)", argv[0], ni_duid_type_to_name(type)); goto cleanup; } } } status = NI_WICKED_RC_ERROR; hex = raw.len ? ni_duid_print_hex(&raw) : NULL; if (ni_string_empty(hex)) { fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); goto cleanup; } if (update) { status = ni_do_duid_create_update(scope, hex); if (status != NI_WICKED_RC_SUCCESS) { fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); goto cleanup; } } printf("%s\t%s\n", scope ? scope : "default", hex); status = NI_WICKED_RC_SUCCESS; cleanup: return status; }
static ni_bool_t dhcp4_tester_req_xml_init(ni_dhcp4_request_t *req, xml_document_t *doc) { xml_node_t *xml, *child; const char *type; xml = xml_document_root(doc); if (xml && !xml->name && xml->children) xml = xml->children; if (!xml || !ni_string_eq(xml->name, "request")) { ni_error("Invalid dhcp4 request xml '%s'", xml ? xml_node_location(xml) : NULL); return FALSE; } type = xml_node_get_attr(xml, "type"); if (ni_string_eq(type, "offer")) { req->dry_run = NI_DHCP4_RUN_OFFER; } else if (ni_string_eq(type, "lease")) { req->dry_run = NI_DHCP4_RUN_LEASE; } for (child = xml->children; child; child = child->next) { if (ni_string_eq(child->name, "uuid")) { if (ni_uuid_parse(&req->uuid, child->cdata) != 0) goto failure; } else if (ni_string_eq(child->name, "acquire-timeout")) { if (ni_parse_uint(child->cdata, &req->acquire_timeout, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "hostname")) { if (!ni_check_domain_name(child->cdata, ni_string_len(child->cdata), 0)) goto failure; ni_string_dup(&req->hostname, child->cdata); } else if (ni_string_eq(child->name, "clientid")) { ni_opaque_t duid; if (ni_parse_hex(child->cdata, duid.data, sizeof(duid.data)) <= 0) goto failure; ni_string_dup(&req->clientid, child->cdata); } else if(ni_string_eq(child->name, "start-delay")) { if (ni_parse_uint(child->cdata, &req->start_delay, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "lease-time")) { if (ni_parse_uint(child->cdata, &req->lease_time, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "recover-lease")) { if (ni_parse_boolean(child->cdata, &req->recover_lease) != 0) goto failure; } else if (ni_string_eq(child->name, "release-lease")) { if (ni_parse_boolean(child->cdata, &req->release_lease) != 0) goto failure; } } return TRUE; failure: if (child) { ni_error("Cannot parse dhcp4 request '%s': %s", child->name, xml_node_location(child)); } return FALSE; }
static int ni_do_duid_create_uuid(int argc, char **argv) { enum { OPT_HELP = 'h', OPT_SCOPE = 's', OPT_UPDATE = 'u', OPT_MACHINE_ID = 'm', OPT_PRODUCT_ID = 'p' }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "scope", required_argument, NULL, OPT_SCOPE }, { "update", no_argument, NULL, OPT_UPDATE }, { "machine-id", optional_argument, NULL, OPT_MACHINE_ID }, { "product-id", optional_argument, NULL, OPT_PRODUCT_ID }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; const char *scope = NULL; ni_bool_t update = FALSE; unsigned int type = 0; const char *from = NULL; const char *hex = NULL; ni_opaque_t raw; optind = 1; while ((opt = getopt_long(argc, argv, "+hs:um::p::", options, NULL)) != EOF) { switch (opt) { case OPT_MACHINE_ID: type = OPT_MACHINE_ID; from = optarg; break; case OPT_PRODUCT_ID: type = OPT_PRODUCT_ID; from = optarg; break; case OPT_UPDATE: update = TRUE; break; case OPT_SCOPE: if (optarg && !ni_string_eq(optarg, "default")) scope = optarg; break; case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "Usage: %s [options] [uuid]\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" " --scope <ifname> create device specific duid instead of default\n" " --update create a duid and update duid map file\n" " --machine-id[=FILE] import uuid from /etc/machine-id file\n" " --product-id[=FILE] import uuid from dmi product-id sysfs file\n" "\n" "Arguments:\n" " uuid create duid using specified uuid-string\n" "\n", argv[0]); goto cleanup; } } switch (type) { case OPT_MACHINE_ID: case OPT_PRODUCT_ID: if ((argc - optind) != 0) goto usage; break; default: if ((argc - optind) != 1) goto usage; from = argv[optind++]; break; } status = NI_WICKED_RC_ERROR; if (scope && !ni_netdev_name_is_valid(scope)) { fprintf(stderr, "%s: invalid scope interface name '%s'\n", argv[0], ni_print_suspect(scope, ni_string_len(scope))); goto cleanup; } switch (type) { case OPT_MACHINE_ID: if (!ni_duid_create_uuid_machine_id(&raw, from)) { fprintf(stderr, "%s: cannot create duid by importing uuid from machine-id%s%s", argv[0], from ? " file ": "", from ? from : ""); goto cleanup; } break; case OPT_PRODUCT_ID: if (!ni_duid_create_uuid_dmi_product_id(&raw, from)) { fprintf(stderr, "%s: cannot create duid by importing uuid from dmi product-id%s%s", argv[0], from ? " file ": "", from ? from : ""); goto cleanup; } break; default: if (!ni_duid_create_uuid_string(&raw, from)) { fprintf(stderr, "%s: cannot create duid by importing uuid string '%s'", argv[0], from); goto cleanup; } break; } hex = raw.len ? ni_duid_print_hex(&raw) : NULL; if (ni_string_empty(hex)) { fprintf(stderr, "%s: cannot format en duid as a colon-separated hex string\n", argv[0]); goto cleanup; } if (update) { status = ni_do_duid_create_update(scope, hex); if (status != NI_WICKED_RC_SUCCESS) { fprintf(stderr, "%s: cannot update duid map file using the created duid\n", argv[0]); goto cleanup; } } printf("%s\t%s\n", scope ? scope : "default", hex); status = NI_WICKED_RC_SUCCESS; cleanup: return status; }
static int __ni_config_parse_dhcp6_vendor_opt_node(xml_node_t *node, ni_var_array_t *opts, const char *parent) { const char *attrval; const char *code = NULL; enum { FORMAT_STR, /* normal string */ FORMAT_HEX, /* XX:XX format */ }; int format = FORMAT_STR; size_t len; if (strcmp(node->name, "option")) { ni_error("config: <%s> is not a valid <%s> option node", node->name, parent); return -1; } if ((attrval = xml_node_get_attr(node, "code")) != NULL) { char * err; long num; num = strtol(attrval, &err, 0); if (*err != '\0' || num < 0 || num > 0xffff) { ni_error("config: unable to parse %s <option code=\"%s\"", parent, attrval); return -1; } code = attrval; } else { ni_error("config: missed %s <option> without code attribute", parent); return -1; } if ((attrval = xml_node_get_attr(node, "format")) != NULL) { if (!strcmp(attrval, "hex") || !strcmp(attrval, "mac")) { format = FORMAT_HEX; } else if (!strcmp(attrval, "str") || !strcmp(attrval, "string")) { format = FORMAT_STR; } else { ni_error("config: unknown %s <option format=\"%s\"", parent, attrval); return -1; } } len = ni_string_len(node->cdata); if(format == FORMAT_HEX) { unsigned char *buf; /* verify the format early ... */ if (len > 0) { len = (len / 3) + 1; buf = xcalloc(1, len); if (ni_parse_hex(node->cdata, buf, len) <= 0) { ni_error("config: unable to parse %s hex option data", parent); free(buf); return -1; } free(buf); } ni_var_array_set(opts, code, node->cdata); } else { ni_stringbuf_t buf = NI_STRINGBUF_INIT_DYNAMIC; /* convert to hex-string format */ if (len > 0) { ni_stringbuf_grow(&buf, (len * 3)); ni_format_hex((unsigned char *)node->cdata, len, buf.string, buf.size); } ni_var_array_set(opts, code, buf.string); ni_stringbuf_destroy(&buf); } return 0; }
/* * Decode an RFC3397 DNS search order option. */ static int ni_dhcp_decode_dnssearch(ni_buffer_t *optbuf, ni_string_array_t *list, const char *what) { ni_stringbuf_t namebuf = NI_STRINGBUF_INIT_DYNAMIC; unsigned char *base = ni_buffer_head(optbuf); unsigned int base_offset = optbuf->head; size_t len; ni_string_array_destroy(list); while (ni_buffer_count(optbuf) && !optbuf->underflow) { ni_buffer_t *bp = optbuf; ni_buffer_t jumpbuf; while (1) { unsigned int pos = bp->head - base_offset; unsigned int pointer; char label[64]; int length; if ((length = ni_buffer_getc(bp)) < 0) goto failure; /* unexpected EOF */ if (length == 0) break; /* end of this name */ switch (length & 0xC0) { case 0: /* Plain name component */ if (ni_buffer_get(bp, label, length) < 0) goto failure; label[length] = '\0'; if (!ni_stringbuf_empty(&namebuf)) ni_stringbuf_putc(&namebuf, '.'); ni_stringbuf_puts(&namebuf, label); break; case 0xC0: /* Pointer */ pointer = (length & 0x3F) << 8; if ((length = ni_buffer_getc(bp)) < 0) goto failure; pointer |= length; if (pointer >= pos) goto failure; ni_buffer_init_reader(&jumpbuf, base, pos); jumpbuf.head = pointer; bp = &jumpbuf; break; default: goto failure; } } if (!ni_stringbuf_empty(&namebuf)) { len = ni_string_len(namebuf.string); if (ni_check_domain_name(namebuf.string, len, 0)) { ni_string_array_append(list, namebuf.string); } else { ni_debug_dhcp("Discarded suspect %s: %s", what, ni_print_suspect(namebuf.string, len)); } } ni_stringbuf_destroy(&namebuf); } return 0; failure: ni_stringbuf_destroy(&namebuf); ni_string_array_destroy(list); return -1; }
/* * Parse a DHCP response. * FIXME: RFC2131 states that the server is allowed to split a DHCP option into * several (partial) options if the total length exceeds 255 octets. We don't * handle this yet. */ int ni_dhcp_parse_response(const ni_dhcp_message_t *message, ni_buffer_t *options, ni_addrconf_lease_t **leasep) { ni_buffer_t overload_buf; ni_addrconf_lease_t *lease; ni_route_array_t default_routes = NI_ROUTE_ARRAY_INIT; ni_route_array_t static_routes = NI_ROUTE_ARRAY_INIT; ni_route_array_t classless_routes = NI_ROUTE_ARRAY_INIT; ni_string_array_t dns_servers = NI_STRING_ARRAY_INIT; ni_string_array_t dns_search = NI_STRING_ARRAY_INIT; ni_string_array_t nis_servers = NI_STRING_ARRAY_INIT; char *nisdomain = NULL; char *dnsdomain = NULL; int opt_overload = 0; int msg_type = -1; int use_bootserver = 1; int use_bootfile = 1; lease = ni_addrconf_lease_new(NI_ADDRCONF_DHCP, AF_INET); lease->state = NI_ADDRCONF_STATE_GRANTED; lease->type = NI_ADDRCONF_DHCP; lease->family = AF_INET; lease->time_acquired = time(NULL); lease->dhcp.address.s_addr = message->yiaddr; lease->dhcp.serveraddress.s_addr = message->siaddr; lease->dhcp.address.s_addr = message->yiaddr; parse_more: /* Loop as long as we still have data in the buffer. */ while (ni_buffer_count(options) && !options->underflow) { ni_buffer_t buf; int option; option = ni_dhcp_option_next(options, &buf); //ni_debug_dhcp("handle option %s (%d)", ni_dhcp_option_name(option), option); if (option == DHCP_PAD) continue; if (option == DHCP_END) break; if (option < 0) goto error; if (ni_buffer_count(&buf) == 0) { ni_error("option %d has zero length", option); goto error; } switch (option) { case DHCP_MESSAGETYPE: msg_type = ni_buffer_getc(&buf); if (msg_type < 0) goto error; continue; case DHCP_ADDRESS: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.address); break; case DHCP_NETMASK: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.netmask); break; case DHCP_BROADCAST: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.broadcast); break; case DHCP_SERVERIDENTIFIER: ni_dhcp_option_get_ipv4(&buf, &lease->dhcp.serveraddress); break; case DHCP_LEASETIME: ni_dhcp_option_get32(&buf, &lease->dhcp.lease_time); break; case DHCP_RENEWALTIME: ni_dhcp_option_get32(&buf, &lease->dhcp.renewal_time); break; case DHCP_REBINDTIME: ni_dhcp_option_get32(&buf, &lease->dhcp.rebind_time); break; case DHCP_MTU: ni_dhcp_option_get16(&buf, &lease->dhcp.mtu); /* Minimum legal mtu is 68 accoridng to * RFC 2132. In practise it's 576 which is the * minimum maximum message size. */ if (lease->dhcp.mtu < MTU_MIN) { ni_debug_dhcp("MTU %u is too low, minimum is %d; ignoring", lease->dhcp.mtu, MTU_MIN); lease->dhcp.mtu = 0; } break; case DHCP_HOSTNAME: ni_dhcp_option_get_domain(&buf, &lease->hostname, "hostname"); break; case DHCP_DNSDOMAIN: ni_dhcp_option_get_domain(&buf, &dnsdomain, "dns-domain"); break; case DHCP_MESSAGE: ni_dhcp_option_get_printable(&buf, &lease->dhcp.message, "dhcp-message"); break; case DHCP_ROOTPATH: ni_dhcp_option_get_pathname(&buf, &lease->dhcp.rootpath, "root-path"); break; case DHCP_NISDOMAIN: ni_dhcp_option_get_domain(&buf, &nisdomain, "nis-domain"); break; case DHCP_NETBIOSNODETYPE: ni_dhcp_option_get_netbios_type(&buf, &lease->netbios_type); break; case DHCP_NETBIOSSCOPE: ni_dhcp_option_get_domain(&buf, &lease->netbios_scope, "netbios-scope"); break; case DHCP_DNSSERVER: ni_dhcp_decode_address_list(&buf, &dns_servers); break; case DHCP_NTPSERVER: ni_dhcp_decode_address_list(&buf, &lease->ntp_servers); break; case DHCP_NISSERVER: ni_dhcp_decode_address_list(&buf, &nis_servers); break; case DHCP_LPRSERVER: ni_dhcp_decode_address_list(&buf, &lease->lpr_servers); break; case DHCP_LOGSERVER: ni_dhcp_decode_address_list(&buf, &lease->log_servers); break; case DHCP_NETBIOSNAMESERVER: ni_dhcp_decode_address_list(&buf, &lease->netbios_name_servers); break; case DHCP_NETBIOSDDSERVER: ni_dhcp_decode_address_list(&buf, &lease->netbios_dd_servers); break; case DHCP_DNSSEARCH: ni_dhcp_decode_dnssearch(&buf, &dns_search, "dns-search domain"); break; case DHCP_CSR: case DHCP_MSCSR: ni_route_array_destroy(&classless_routes); if (ni_dhcp_decode_csr(&buf, &classless_routes) < 0) goto error; break; case DHCP_SIPSERVER: ni_dhcp_decode_sipservers(&buf, &lease->sip_servers); break; case DHCP_STATICROUTE: ni_route_array_destroy(&static_routes); if (ni_dhcp_decode_static_routes(&buf, &static_routes) < 0) goto error; break; case DHCP_ROUTERS: ni_route_array_destroy(&default_routes); if (ni_dhcp_decode_routers(&buf, &default_routes) < 0) goto error; break; case DHCP_OPTIONSOVERLOADED: if (options != &overload_buf) { opt_overload = ni_buffer_getc(&buf); } else { ni_debug_dhcp("DHCP: ignoring OVERLOAD option in overloaded data"); (void) ni_buffer_getc(&buf); } break; case DHCP_FQDN: /* We ignore replies about FQDN */ break; default: ni_debug_dhcp("ignoring unsupported DHCP code %u", option); break; } if (buf.underflow) { ni_debug_dhcp("unable to parse DHCP option %s: too short", ni_dhcp_option_name(option)); goto error; } else if (ni_buffer_count(&buf)) { ni_debug_dhcp("excess data in DHCP option %s - %u bytes left", ni_dhcp_option_name(option), ni_buffer_count(&buf)); } } if (options->underflow) { ni_debug_dhcp("unable to parse DHCP response: truncated packet"); goto error; } if (opt_overload) { const void *more_data = NULL; size_t size = 0; if (opt_overload & DHCP_OVERLOAD_BOOTFILE) { use_bootfile = 0; more_data = message->bootfile; size = sizeof(message->bootfile); opt_overload &= ~DHCP_OVERLOAD_BOOTFILE; } else if (opt_overload & DHCP_OVERLOAD_SERVERNAME) { use_bootserver = 0; more_data = message->servername; size = sizeof(message->servername); opt_overload &= ~DHCP_OVERLOAD_SERVERNAME; } else { opt_overload = 0; } if (more_data) { ni_buffer_init_reader(&overload_buf, (void *) more_data, size); options = &overload_buf; goto parse_more; } } if (use_bootserver && message->servername[0]) { char tmp[sizeof(message->servername)]; size_t len; assert(sizeof(lease->dhcp.servername) == sizeof(message->servername)); memcpy(tmp, message->servername, sizeof(tmp)); tmp[sizeof(tmp)-1] = '\0'; len = ni_string_len(tmp); if (ni_check_domain_name(tmp, len, 0)) { memcpy(lease->dhcp.servername, tmp, sizeof(lease->dhcp.servername)); } else { ni_debug_dhcp("Discarded suspect boot-server name: %s", ni_print_suspect(tmp, len)); } } if (use_bootfile && message->bootfile[0]) { char tmp[sizeof(message->bootfile)]; size_t len; memcpy(tmp, message->bootfile, sizeof(tmp)); tmp[sizeof(tmp)-1] = '\0'; len = ni_string_len(tmp); if (ni_check_pathname(tmp, len)) { ni_string_dup(&lease->dhcp.bootfile, tmp); } else { ni_debug_dhcp("Discarded suspect boot-file name: %s", ni_print_suspect(tmp, len)); } } /* Fill in any missing fields */ if (!lease->dhcp.netmask.s_addr) { unsigned int pfxlen = guess_prefix_len(lease->dhcp.address); lease->dhcp.netmask.s_addr = htonl(~(0xFFFFFFFF >> pfxlen)); }
static int __ni_config_parse_dhcp6_class_data(xml_node_t *node, ni_string_array_t *data, const char *parent) { const char *attrval; enum { FORMAT_STR, /* normal string */ FORMAT_HEX, /* XX:XX format */ }; int format = FORMAT_STR; size_t len; if (strcmp(node->name, "class-data")) { ni_error("config: <%s> is not a valid <%s> class-data node", node->name, parent); return -1; } len = ni_string_len(node->cdata); if (len == 0) { ni_warn("config: empty %s <class-data> node", parent); return 0; } if ((attrval = xml_node_get_attr(node, "format")) != NULL) { if (!strcmp(attrval, "hex") || !strcmp(attrval, "mac")) { format = FORMAT_HEX; } else if (!strcmp(attrval, "str") || !strcmp(attrval, "string")) { format = FORMAT_STR; } else { ni_error("config: unknown %s <class-data format=\"%s\"", parent, attrval); return -1; } } if(format == FORMAT_HEX) { unsigned char *buf; /* verify the format early ... */ len = (len / 3) + 1; buf = xcalloc(1, len); if (ni_parse_hex(node->cdata, buf, len) <= 0) { ni_error("config: unable to parse %s hex class-data", parent); free(buf); return -1; } free(buf); ni_string_array_append(data, node->cdata); } else { ni_stringbuf_t buf = NI_STRINGBUF_INIT_DYNAMIC; /* convert to hex-string format */ ni_stringbuf_grow(&buf, (len * 3)); ni_format_hex((unsigned char *)node->cdata, len, buf.string, buf.size); ni_string_array_append(data, buf.string); ni_stringbuf_destroy(&buf); } return 0; }
static ni_bool_t __ni_compat_generate_wireless(xml_node_t *ifnode, const ni_compat_netdev_t *compat) { ni_wireless_t *wlan; ni_wireless_network_t *net; xml_node_t *wireless, *network, *wep, *wpa_psk, *wpa_eap; ni_wireless_blob_t *cert; char *tmp = NULL; const char *value; int i, count, key_i; wlan = ni_netdev_get_wireless(compat->dev); if (!(wireless = xml_node_create(ifnode, "wireless"))) { return FALSE; } if (ni_string_len(wlan->conf.country) == 2) { xml_node_new_element("country", wireless, wlan->conf.country); } if (wlan->conf.ap_scan <= NI_WIRELESS_AP_SCAN_SUPPLICANT_EXPLICIT_MATCH && ni_string_printf(&tmp, "%u", wlan->conf.ap_scan)) { xml_node_new_element("ap-scan", wireless, tmp); ni_string_free(&tmp); } if (!ni_string_empty(wlan->conf.driver)) xml_node_new_element("wpa-driver", wireless, wlan->conf.driver); count = wlan->conf.networks.count; for (i = 0; i < count; i++) { net = wlan->conf.networks.data[i]; if (!(network = xml_node_new("network", wireless))) return FALSE; if (net->essid.len > 0) { ni_string_set(&tmp, (const char *) net->essid.data, net->essid.len); xml_node_new_element("essid", network, tmp); ni_string_free(&tmp); } xml_node_new_element("scan-ssid", network, net->scan_ssid?"true":"false"); if (net->priority > 0 && ni_string_printf(&tmp, "%u", net->priority)) { xml_node_new_element("priority", network, tmp); ni_string_free(&tmp); } if ((value = ni_wireless_mode_to_name(net->mode))) { xml_node_new_element("mode", network, value); } if (net->access_point.len > 0) { xml_node_new_element("access-point", network, ni_link_address_print(&net->access_point)); } if (net->channel > 0 && ni_string_printf(&tmp, "%u", net->channel)) { xml_node_new_element("channel", network, tmp); ni_string_free(&tmp); } if (net->fragment_size > 0 && ni_string_printf(&tmp, "%u", net->fragment_size)) { xml_node_new_element("fragment-size", network, tmp); ni_string_free(&tmp); } if ((value = ni_wireless_key_management_to_name(net->keymgmt_proto))) { xml_node_new_element("key-management", network, value); } switch (net->keymgmt_proto) { case NI_WIRELESS_KEY_MGMT_NONE: if (!(wep = xml_node_new("wep", network))) { return FALSE; } if ((value = ni_wireless_auth_algo_to_name(net->auth_algo))) { xml_node_new_element("auth-algo", wep, value); } if (net->default_key < NI_WIRELESS_WEP_KEY_COUNT && ni_string_printf(&tmp, "%u", net->default_key)) { xml_node_new_element("default-key", wep, tmp); ni_string_free(&tmp); } for (key_i = 0; key_i < NI_WIRELESS_WEP_KEY_COUNT; key_i++) { if (!ni_string_empty(net->wep_keys[key_i])) { /* To be secured */ xml_node_new_element("key", wep, net->wep_keys[key_i]); } } break; case NI_WIRELESS_KEY_MGMT_PSK: if (!(wpa_psk = xml_node_new("wpa-psk", network))) { return FALSE; } if (!ni_string_empty(net->wpa_psk.passphrase)) { /* To be secured */ xml_node_new_element("passphrase", wpa_psk, net->wpa_psk.passphrase); } if ((value = ni_wireless_auth_mode_to_name(net->auth_proto))) { xml_node_new_element("auth-proto", wpa_psk, value); } if ((value = ni_wireless_cipher_to_name(net->pairwise_cipher))) { xml_node_new_element("pairwise-cipher", wpa_psk, value); } if ((value = ni_wireless_cipher_to_name(net->group_cipher))) { xml_node_new_element("group-cipher", wpa_psk, value); } break; case NI_WIRELESS_KEY_MGMT_EAP: if (!(wpa_eap = xml_node_new("wpa-eap", network))) { return FALSE; } if ((value = ni_wireless_eap_method_to_name(net->wpa_eap.method))) { xml_node_new_element("method", wpa_eap, value); } if ((value = ni_wireless_auth_mode_to_name(net->auth_proto))) { xml_node_new_element("auth-proto", wpa_eap, value); } if ((value = ni_wireless_cipher_to_name(net->pairwise_cipher))) { xml_node_new_element("pairwise-cipher", wpa_eap, value); } if ((value = ni_wireless_cipher_to_name(net->group_cipher))) { xml_node_new_element("group-cipher", wpa_eap, value); } if (!ni_string_empty(net->wpa_eap.identity)) { xml_node_new_element("identity", wpa_eap, net->wpa_eap.identity); } xml_node_t *phase1 = xml_node_new("phase1", wpa_eap); if (ni_string_printf(&tmp, "%u", net->wpa_eap.phase1.peapver)) { xml_node_new_element("peap-version", phase1, tmp); ni_string_free(&tmp); } xml_node_t *phase2 = xml_node_new("phase2", wpa_eap); if ((value = ni_wireless_eap_method_to_name(net->wpa_eap.phase2.method))) { xml_node_new_element("method", phase2, value); } if (!ni_string_empty(net->wpa_eap.phase2.password)) { /* To be secured */ xml_node_new_element("password", phase2, net->wpa_eap.phase2.password); } if (!ni_string_empty(net->wpa_eap.anonid)) { xml_node_new_element("anonid", wpa_eap, net->wpa_eap.anonid); } xml_node_t *tls = xml_node_new("tls", wpa_eap); if ((cert = net->wpa_eap.tls.ca_cert)) { if (!ni_string_empty(cert->name)) { xml_node_new_element("ca-cert", tls, cert->name); /* FIXME/ADDME file data and size exporting */ } } if ((cert = net->wpa_eap.tls.client_cert)) { if (!ni_string_empty(cert->name)) { xml_node_new_element("client-cert", tls, cert->name); /* FIXME/ADDME file data and size exporting */ } } if ((cert = net->wpa_eap.tls.client_key)) { if (!ni_string_empty(cert->name)) { xml_node_new_element("client-key", tls, cert->name); /* FIXME/ADDME file data and size exporting */ } } if (!ni_string_empty(net->wpa_eap.tls.client_key_passwd)) { xml_node_new_element("client-key-passwd", tls, net->wpa_eap.tls.client_key_passwd); /* FIXME/ADDME file data and size exporting */ } break; default: return FALSE; break; } } return TRUE; }