1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2015 Roy Marples <roy (at) marples.name> 4 * All rights reserved 5 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <arpa/inet.h> 29 30 #include <ctype.h> 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <syslog.h> 35 36 #include <dbus/dbus.h> 37 38 #include "../config.h" 39 #include "dbus-dict.h" 40 41 static dbus_bool_t 42 append_sanitized_string(DBusMessageIter *iter, const char *value) 43 { 44 dbus_bool_t ret; 45 int len = strlen(value); 46 char *sanitized_value = NULL; 47 int i; 48 49 for (i = 0; i < len; i++) { 50 if (isascii(value[i]) || isprint(value[i])) { 51 if (sanitized_value) 52 sanitized_value[i] = value[i]; 53 } else { 54 if (sanitized_value == NULL) { 55 sanitized_value = malloc(len + 1); 56 if (sanitized_value == NULL) { 57 syslog(LOG_ERR, "DBus string parameter " 58 "sanitization failed due to " 59 "malloc failure"); 60 return FALSE; 61 } 62 memcpy(sanitized_value, value, i); 63 } 64 sanitized_value[i] = '?'; 65 } 66 } 67 if (sanitized_value) { 68 syslog(LOG_ERR, "DBus string parameter sanitization" 69 " was invoked"); 70 sanitized_value[i] = '\0'; 71 ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, 72 &sanitized_value); 73 74 free(sanitized_value); 75 } else { 76 ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, 77 &value); 78 } 79 80 return ret; 81 } 82 83 static int 84 append_config_value(DBusMessageIter *entry, int type, 85 const char *data) 86 { 87 int retval; 88 DBusMessageIter var; 89 unsigned char byte; 90 dbus_uint16_t u16; 91 dbus_uint32_t u32; 92 dbus_int16_t i16; 93 dbus_int32_t i32; 94 struct in_addr in; 95 96 retval = -1; 97 switch (type) { 98 case DBUS_TYPE_BOOLEAN: 99 if (*data == '0' || *data == '\0') 100 u32 = 0; 101 else 102 u32 = 1; 103 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 104 DBUS_TYPE_BOOLEAN_AS_STRING, &var); 105 if (dbus_message_iter_append_basic(&var, 106 DBUS_TYPE_BOOLEAN, &u32)) 107 retval = 0; 108 break; 109 case DBUS_TYPE_BYTE: 110 byte = strtoul(data, NULL, 0); 111 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 112 DBUS_TYPE_BYTE_AS_STRING, &var); 113 if (dbus_message_iter_append_basic(&var, DBUS_TYPE_BYTE, 114 &byte)) 115 retval = 0; 116 break; 117 case DBUS_TYPE_STRING: 118 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 119 DBUS_TYPE_STRING_AS_STRING, &var); 120 if (append_sanitized_string(&var, data)) 121 retval = 0; 122 break; 123 case DBUS_TYPE_INT16: 124 i16 = strtol(data, NULL, 0); 125 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 126 DBUS_TYPE_INT16_AS_STRING, &var); 127 if (dbus_message_iter_append_basic(&var, 128 DBUS_TYPE_INT16, &i16)) 129 retval = 0; 130 break; 131 case DBUS_TYPE_UINT16: 132 u16 = strtoul(data, NULL, 0); 133 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 134 DBUS_TYPE_UINT16_AS_STRING, &var); 135 if (dbus_message_iter_append_basic(&var, 136 DBUS_TYPE_UINT16, &u16)) 137 retval = 0; 138 break; 139 case DBUS_TYPE_INT32: 140 i32 = strtol(data, NULL, 0); 141 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 142 DBUS_TYPE_INT32_AS_STRING, &var); 143 if (dbus_message_iter_append_basic(&var, 144 DBUS_TYPE_INT32, &i32)) 145 retval = 0; 146 break; 147 case DBUS_TYPE_UINT32: 148 if (strchr(data, '.') != NULL && inet_aton(data, &in) == 1) 149 u32 = in.s_addr; 150 else 151 u32 = strtoul(data, NULL, 0); 152 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, 153 DBUS_TYPE_UINT32_AS_STRING, &var); 154 if (dbus_message_iter_append_basic(&var, 155 DBUS_TYPE_UINT32, &u32)) 156 retval = 0; 157 break; 158 default: 159 retval = 1; 160 break; 161 } 162 if (retval == 0) 163 dbus_message_iter_close_container(entry, &var); 164 else if (retval == 1) 165 retval = 0; 166 167 return retval; 168 } 169 170 static int 171 append_config_byte_array(DBusMessageIter *entry, const char *data) 172 { 173 DBusMessageIter var, array; 174 dbus_bool_t ok = TRUE; 175 uint8_t u8, u8_2; 176 size_t len; 177 const char *it, *end; 178 const char *tsa, *ts; 179 180 tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING; 181 ts = DBUS_TYPE_BYTE_AS_STRING; 182 183 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var); 184 dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array); 185 186 len = strlen(data); 187 it = data; 188 end = data + len; 189 190 /* "a12" is treated as "0a12" */ 191 if (len & 1) { 192 ok = (sscanf(it++, "%1hhx", &u8) == 1) && 193 dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE, 194 &u8); 195 } 196 197 while (ok && it < end) { 198 /* sscanf("1z", "%2hhx", &u8) will store 0x01 in u8 and 199 * will return 1 */ 200 ok = (sscanf(it++, "%1hhx", &u8) == 1) && 201 (sscanf(it++, "%1hhx", &u8_2) == 1); 202 if (!ok) 203 break; 204 205 u8 = (u8 << 4) | u8_2; 206 ok = dbus_message_iter_append_basic(&array, DBUS_TYPE_BYTE, &u8); 207 } 208 209 dbus_message_iter_close_container(&var, &array); 210 dbus_message_iter_close_container(entry, &var); 211 return ok ? 0 : -1; 212 } 213 214 static int 215 append_config_array(DBusMessageIter *entry, int type, const char *data) 216 { 217 int retval; 218 char *ns, *p, *tok; 219 const char *tsa, *ts; 220 DBusMessageIter var, array; 221 dbus_bool_t ok; 222 dbus_uint32_t u32; 223 struct in_addr in; 224 225 if (type == DBUS_TYPE_BYTE) 226 return append_config_byte_array(entry, data); 227 228 switch (type) { 229 case DBUS_TYPE_STRING: 230 tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING; 231 ts = DBUS_TYPE_STRING_AS_STRING; 232 break; 233 case DBUS_TYPE_UINT32: 234 tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING; 235 ts = DBUS_TYPE_UINT32_AS_STRING; 236 break; 237 default: 238 return -1; 239 } 240 241 ns = p = strdup(data); 242 if (ns == NULL) 243 return -1; 244 retval = 0; 245 246 dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var); 247 dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array); 248 while ((tok = strsep(&p, " ")) != NULL) { 249 if (*tok == '\0') 250 continue; 251 switch(type) { 252 case DBUS_TYPE_STRING: 253 ok = append_sanitized_string(&array, tok); 254 break; 255 case DBUS_TYPE_UINT32: 256 if (strchr(tok, '.') != NULL && 257 inet_aton(tok, &in) == 1) 258 u32 = in.s_addr; 259 else 260 u32 = strtoul(tok, NULL, 0); 261 ok = dbus_message_iter_append_basic(&array, 262 DBUS_TYPE_UINT32, &u32); 263 break; 264 default: 265 ok = FALSE; 266 break; 267 } 268 if (!ok) 269 break; 270 } 271 dbus_message_iter_close_container(&var, &array); 272 dbus_message_iter_close_container(entry, &var); 273 free(ns); 274 return retval; 275 } 276 277 int 278 dict_append_config_item(DBusMessageIter *iter, const struct o_dbus *op, 279 const char *data) 280 { 281 int retval; 282 DBusMessageIter entry; 283 284 retval = 0; 285 if (*data == '\0') 286 return retval; 287 dbus_message_iter_open_container(iter, 288 DBUS_TYPE_DICT_ENTRY, 289 NULL, 290 &entry); 291 append_sanitized_string(&entry, op->name); 292 if (op->type == DBUS_TYPE_ARRAY) 293 retval = append_config_array(&entry, op->sub_type, data); 294 else 295 retval = append_config_value(&entry, op->type, data); 296 dbus_message_iter_close_container(iter, &entry); 297 return retval; 298 } 299