Example #1
0
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;
	}
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
File: json.c Project: gsanso/wicked
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++;
		}
	}
Example #7
0
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;
}
Example #8
0
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(&ethtool->priv_flags->names, buf.string) == 0) {
			if (enabled)
				ethtool->priv_flags->bitmap |= NI_BIT(i);
		}
		ni_stringbuf_destroy(&buf);
	}
	return TRUE;
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
0
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;
	}
}
Example #12
0
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;
}
Example #13
0
/*
 * 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;
}
Example #14
0
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;
}
Example #15
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;
}
Example #16
0
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;
}
Example #17
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;
}
Example #18
0
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;
}
Example #19
0
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;
}
Example #20
0
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;
}
Example #21
0
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;
}
Example #22
0
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;
}
Example #23
0
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;
}
Example #24
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;
}
Example #25
0
/*
 * 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));
	}
Example #26
0
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;
}
Example #27
0
File: compat.c Project: mchf/wicked
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;
}