C++程序  |  299行  |  7.8 KB

/*
 * dhcpcd - DHCP client daemon
 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
 * All rights reserved

 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <arpa/inet.h>

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>

#include <dbus/dbus.h>

#include "../config.h"
#include "dbus-dict.h"

static dbus_bool_t
append_sanitized_string(DBusMessageIter *iter, const char *value)
{
	dbus_bool_t ret;
	int len = strlen(value);
	char *sanitized_value = NULL;
	int i;

	for (i = 0; i < len; i++) {
		if (isascii(value[i]) || isprint(value[i])) {
			if (sanitized_value)
				sanitized_value[i] = value[i];
		} else {
			if (sanitized_value == NULL) {
				sanitized_value = malloc(len + 1);
				if (sanitized_value == NULL) {
					syslog(LOG_ERR, "DBus string parameter "
					       "sanitization failed due to "
					       "malloc failure");
					return FALSE;
				}
				memcpy(sanitized_value, value, i);
			}
			sanitized_value[i] = '?';
		}
	}
	if (sanitized_value) {
		syslog(LOG_ERR, "DBus string parameter sanitization"
                       " was invoked");
		sanitized_value[i] = '\0';
		ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
	            &sanitized_value);

		free(sanitized_value);
	} else {
		ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
	            &value);
	}

	return ret;
}

static int
append_config_value(DBusMessageIter *entry, int type,
    const char *data)
{
	int retval;
	DBusMessageIter var;
	unsigned char byte;
	dbus_uint16_t u16;
	dbus_uint32_t u32;
	dbus_int16_t i16;
	dbus_int32_t i32;
	struct in_addr in;

	retval = -1;
	switch (type) {
	case DBUS_TYPE_BOOLEAN:
		if (*data == '0' || *data == '\0')
			u32 = 0;
		else
			u32 = 1;
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_BOOLEAN_AS_STRING, &var);
		if (dbus_message_iter_append_basic(&var,
			DBUS_TYPE_BOOLEAN, &u32))
			retval = 0;
		break;
	case DBUS_TYPE_BYTE:
		byte = strtoul(data, NULL, 0);
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_BYTE_AS_STRING, &var);
		if (dbus_message_iter_append_basic(&var, DBUS_TYPE_BYTE,
			&byte))
			retval = 0;
		break;
	case DBUS_TYPE_STRING:
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_STRING_AS_STRING, &var);
		if (append_sanitized_string(&var, data))
			retval = 0;
		break;
	case DBUS_TYPE_INT16:
		i16 = strtol(data, NULL, 0);
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_INT16_AS_STRING, &var);
		if (dbus_message_iter_append_basic(&var,
			DBUS_TYPE_INT16, &i16))
			retval = 0;
		break;
	case DBUS_TYPE_UINT16:
		u16 = strtoul(data, NULL, 0);
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_UINT16_AS_STRING, &var);
		if (dbus_message_iter_append_basic(&var,
			DBUS_TYPE_UINT16, &u16))
			retval = 0;
		break;
	case DBUS_TYPE_INT32:
		i32 = strtol(data, NULL, 0);
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_INT32_AS_STRING, &var);
		if (dbus_message_iter_append_basic(&var,
			DBUS_TYPE_INT32, &i32))
			retval = 0;
		break;
	case DBUS_TYPE_UINT32:
		if (strchr(data, '.') != NULL && inet_aton(data, &in) == 1)
			u32 = in.s_addr;
		else
			u32 = strtoul(data, NULL, 0);
		dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
		    DBUS_TYPE_UINT32_AS_STRING, &var);
		if (dbus_message_iter_append_basic(&var,
			DBUS_TYPE_UINT32, &u32))
			retval = 0;
		break;
	default:
		retval = 1;
		break;
	}
	if (retval == 0)
		dbus_message_iter_close_container(entry, &var);
	else if (retval == 1)
		retval = 0;

	return retval;
}

static int
append_config_byte_array(DBusMessageIter *entry, const char *data)
{
	DBusMessageIter var, array;
	dbus_bool_t ok = TRUE;
	uint8_t u8, u8_2;
	size_t len;
	const char *it, *end;
	const char *tsa, *ts;

	tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING;
	ts = DBUS_TYPE_BYTE_AS_STRING;

	dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var);
	dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array);

	len = strlen(data);
	it = data;
	end = data + len;

	/* "a12" is treated as "0a12" */
	if (len & 1) {
		ok = (sscanf(it++, "%1hhx", &u8) == 1) &&
			dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE,
						       &u8);
	}

	while (ok && it < end) {
		/* sscanf("1z", "%2hhx", &u8) will store 0x01 in u8 and
		 * will return 1 */
		ok = (sscanf(it++, "%1hhx", &u8) == 1) &&
			(sscanf(it++, "%1hhx", &u8_2) == 1);
		if (!ok)
			break;

		u8 = (u8 << 4) | u8_2;
		ok = dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE, &u8);
	}

	dbus_message_iter_close_container(&var, &array);
	dbus_message_iter_close_container(entry, &var);
	return ok ? 0 : -1;
}

static int
append_config_array(DBusMessageIter *entry, int type, const char *data)
{
	int retval;
	char *ns, *p, *tok;
	const char *tsa, *ts;
	DBusMessageIter var, array;
	dbus_bool_t ok;
	dbus_uint32_t u32;
	struct in_addr in;

	if (type == DBUS_TYPE_BYTE)
		return append_config_byte_array(entry, data);

	switch (type) {
	case DBUS_TYPE_STRING:
		tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
		ts = DBUS_TYPE_STRING_AS_STRING;
		break;
	case DBUS_TYPE_UINT32:
		tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING;
		ts = DBUS_TYPE_UINT32_AS_STRING;
		break;
	default:
		return -1;
	}

	ns = p = strdup(data);
	if (ns == NULL)
		return -1;
	retval = 0;

	dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var);
	dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array);
	while ((tok = strsep(&p, " ")) != NULL) {
		if (*tok == '\0')
			continue;
		switch(type) {
		case DBUS_TYPE_STRING:
			ok = append_sanitized_string(&array, tok);
			break;
		case DBUS_TYPE_UINT32:
			if (strchr(tok, '.') != NULL &&
			    inet_aton(tok, &in) == 1)
				u32 = in.s_addr;
			else
				u32 = strtoul(tok, NULL, 0);
			ok = dbus_message_iter_append_basic(&array,
			    DBUS_TYPE_UINT32, &u32);
			break;
		default:
			ok = FALSE;
			break;
		}
		if (!ok)
			break;
	}
	dbus_message_iter_close_container(&var, &array);
	dbus_message_iter_close_container(entry, &var);
	free(ns);
	return retval;
}

int
dict_append_config_item(DBusMessageIter *iter, const struct o_dbus *op,
    const char *data)
{
	int retval;
	DBusMessageIter entry;

	retval = 0;
	if (*data == '\0')
		return retval;
	dbus_message_iter_open_container(iter,
	    DBUS_TYPE_DICT_ENTRY,
	    NULL,
	    &entry);
	append_sanitized_string(&entry, op->name);
	if (op->type == DBUS_TYPE_ARRAY)
		retval = append_config_array(&entry, op->sub_type, data);
	else
		retval = append_config_value(&entry, op->type, data);
	dbus_message_iter_close_container(iter, &entry);
	return retval;
}