1 /* 2 * Copyright (c) 2003-2024 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 13 * contributors may be used to endorse or promote products derived from this 14 * software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "dnssd_ipc.h" 29 30 #if defined(_WIN32) 31 32 #include <stdint.h> 33 34 char *win32_strerror(int inErrorCode) 35 { 36 static char buffer[1024]; 37 DWORD n; 38 memset(buffer, 0, sizeof(buffer)); 39 n = FormatMessageA( 40 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 41 NULL, 42 (DWORD) inErrorCode, 43 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 44 buffer, 45 sizeof(buffer), 46 NULL); 47 if (n > 0) 48 { 49 // Remove any trailing CR's or LF's since some messages have them. 50 while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1])) 51 buffer[--n] = '\0'; 52 } 53 return buffer; 54 } 55 56 #endif 57 58 #include "mdns_strict.h" 59 60 static uint8_t *_write_big32(uint8_t *ptr, const uint32_t u32) 61 { 62 *ptr++ = (uint8_t)((u32 >> 24) & 0xFF); 63 *ptr++ = (uint8_t)((u32 >> 16) & 0xFF); 64 *ptr++ = (uint8_t)((u32 >> 8) & 0xFF); 65 *ptr++ = (uint8_t)( u32 & 0xFF); 66 return ptr; 67 } 68 69 void put_uint32(const uint32_t u32, uint8_t **const ptr) 70 { 71 *ptr = _write_big32(*ptr, u32); 72 } 73 74 #define _assign_null_safe(PTR, VALUE) \ 75 do \ 76 { \ 77 if ((PTR)) \ 78 { \ 79 *(PTR) = (VALUE); \ 80 } \ 81 } while (0) 82 83 static uint32_t _read_big32(const uint8_t *ptr, const uint8_t **const out_end) 84 { 85 uint32_t u32 = 0; 86 u32 |= ((uint32_t)*ptr++) << 24; 87 u32 |= ((uint32_t)*ptr++) << 16; 88 u32 |= ((uint32_t)*ptr++) << 8; 89 u32 |= ((uint32_t)*ptr++); 90 _assign_null_safe(out_end, ptr); 91 return u32; 92 } 93 94 uint32_t get_uint32(const uint8_t **const ptr, const uint8_t *const end) 95 { 96 if (!*ptr || *ptr + sizeof(uint32_t) > end) 97 { 98 *ptr = NULL; 99 return(0); 100 } 101 else 102 { 103 return _read_big32(*ptr, ptr); 104 } 105 } 106 107 static uint8_t *_write_big16(uint8_t *ptr, const uint16_t u16) 108 { 109 *ptr++ = (uint8_t)((u16 >> 8) & 0xFF); 110 *ptr++ = (uint8_t)( u16 & 0xFF); 111 return ptr; 112 } 113 114 void put_uint16(const uint16_t u16, uint8_t **const ptr) 115 { 116 *ptr = _write_big16(*ptr, u16); 117 } 118 119 static uint16_t _read_big16(const uint8_t *ptr, const uint8_t **const out_end) 120 { 121 uint16_t u16 = 0; 122 u16 |= ((uint16_t)*ptr++) << 8; 123 u16 |= ((uint16_t)*ptr++); 124 _assign_null_safe(out_end, ptr); 125 return u16; 126 } 127 128 uint16_t get_uint16(const uint8_t **ptr, const uint8_t *const end) 129 { 130 if (!*ptr || *ptr + sizeof(uint16_t) > end) 131 { 132 *ptr = NULL; 133 return(0); 134 } 135 else 136 { 137 return _read_big16(*ptr, ptr); 138 } 139 } 140 141 int put_string(const char *str, uint8_t **const ptr) 142 { 143 size_t len; 144 if (!str) str = ""; 145 len = strlen(str) + 1; 146 memcpy(*ptr, str, len); 147 *ptr += len; 148 return 0; 149 } 150 151 int get_string(const uint8_t **const ptr, const uint8_t *const end, char *buffer, size_t buflen) 152 { 153 if (!*ptr) 154 { 155 *buffer = 0; 156 return(-1); 157 } 158 else 159 { 160 const char *const lim = buffer + buflen; // Calculate limit 161 while (*ptr < end && buffer < lim) 162 { 163 const uint8_t c = *(*ptr)++; 164 *buffer++ = (char)c; 165 if (c == 0) return(0); // Success 166 } 167 if (buffer == lim) buffer--; 168 *buffer = 0; // Failed, so terminate string, 169 *ptr = NULL; // clear pointer, 170 return(-1); // and return failure indication 171 } 172 } 173 174 void put_rdata(const size_t rdlen, const uint8_t *const rdata, uint8_t **const ptr) 175 { 176 memcpy(*ptr, rdata, rdlen); 177 *ptr += rdlen; 178 } 179 180 const uint8_t *get_rdata(const uint8_t **const ptr, const uint8_t *const end, int rdlen) 181 { 182 if (!*ptr || *ptr + rdlen > end) 183 { 184 *ptr = NULL; 185 return(0); 186 } 187 else 188 { 189 const uint8_t *const rd = *ptr; 190 *ptr += rdlen; 191 return rd; 192 } 193 } 194 195 #define IPC_TLV16_OVERHEAD_LENGTH (2 + 2) // 2 bytes for 16-bit type + 2 bytes for 16-bit length 196 197 size_t get_required_tlv_length(const uint16_t value_length) 198 { 199 return (IPC_TLV16_OVERHEAD_LENGTH + value_length); 200 } 201 202 size_t get_required_tlv_string_length(const char *str_value) 203 { 204 return (IPC_TLV16_OVERHEAD_LENGTH + strlen(str_value) + 1); 205 } 206 207 size_t get_required_tlv_uint8_length(void) 208 { 209 return (IPC_TLV16_OVERHEAD_LENGTH + 1); 210 } 211 212 size_t get_required_tlv_uint32_length(void) 213 { 214 return (IPC_TLV16_OVERHEAD_LENGTH + 4); 215 } 216 217 static size_t _tlv16_set(uint8_t *const dst, const uint8_t *const limit, const uint16_t type, const uint16_t length, 218 const uint8_t *const value, uint8_t **const out_end) 219 { 220 uint8_t *ptr = dst; 221 const size_t required_len = IPC_TLV16_OVERHEAD_LENGTH + length; 222 mdns_require_quiet(ptr, exit); 223 mdns_require_quiet(ptr <= limit, exit); 224 mdns_require_quiet((size_t)(limit - ptr) >= required_len, exit); 225 226 ptr = _write_big16(ptr, type); 227 ptr = _write_big16(ptr, length); 228 if (length > 0) 229 { 230 memcpy(ptr, value, length); 231 ptr += length; 232 } 233 234 exit: 235 mdns_assign(out_end, ptr); 236 return required_len; 237 } 238 239 size_t put_tlv(const uint16_t type, const uint16_t length, const uint8_t *const value, uint8_t **const ptr, 240 const uint8_t *const limit) 241 { 242 uint8_t *const dst = ptr ? *ptr : NULL; 243 return _tlv16_set(dst, limit, type, length, value, ptr); 244 } 245 246 void put_tlv_string(const uint16_t type, const char *const str_value, uint8_t **const ptr, const uint8_t *const limit, 247 int *const out_error) 248 { 249 int err = -1; 250 size_t len = strlen(str_value) + 1; 251 if (len <= UINT16_MAX) 252 { 253 put_tlv(type, (uint16_t)len, (const uint8_t *)str_value, ptr, limit); 254 err = 0; 255 } 256 _assign_null_safe(out_error, err); 257 } 258 259 void put_tlv_uint8(const uint16_t type, const uint8_t u8, uint8_t **const ptr, const uint8_t *const limit) 260 { 261 put_tlv(type, sizeof(u8), &u8, ptr, limit); 262 } 263 264 void put_tlv_uint16(const uint16_t type, const uint16_t u16, uint8_t **const ptr, const uint8_t *const limit) 265 { 266 uint8_t value[2]; 267 _write_big16(value, u16); 268 put_tlv(type, sizeof(value), value, ptr, limit); 269 } 270 271 size_t put_tlv_uint32(const uint16_t type, const uint32_t u32, uint8_t **const ptr, const uint8_t *const limit) 272 { 273 uint8_t value[4]; 274 _write_big32(value, u32); 275 return put_tlv(type, sizeof(value), value, ptr, limit); 276 } 277 278 size_t put_tlv_uuid(const uint16_t type, const uint8_t uuid[MDNS_STATIC_ARRAY_PARAM MDNS_UUID_SIZE], uint8_t **const ptr, 279 const uint8_t *const limit) 280 { 281 return put_tlv(type, MDNS_UUID_SIZE, uuid, ptr, limit); 282 } 283 284 static const uint8_t *_tlv16_get_next(const uint8_t *ptr, const uint8_t *const end, uint16_t *const out_type, 285 size_t *const out_length, const uint8_t **const out_ptr) 286 { 287 if ((end - ptr) >= IPC_TLV16_OVERHEAD_LENGTH) 288 { 289 const uint16_t type = _read_big16(ptr, &ptr); 290 const uint16_t length = _read_big16(ptr, &ptr); 291 const uint8_t *const value = ptr; 292 if ((end - value) >= length) 293 { 294 ptr += length; 295 _assign_null_safe(out_type, type); 296 _assign_null_safe(out_length, length); 297 _assign_null_safe(out_ptr, ptr); 298 return value; 299 } 300 } 301 return NULL; 302 } 303 304 static const uint8_t *_tlv16_get_value(const uint8_t *const start, const uint8_t *const end, const uint16_t desired_type, 305 size_t *const out_length, const uint8_t **const out_ptr) 306 { 307 const uint8_t *ptr = start; 308 uint16_t type; 309 size_t length; 310 const uint8_t *value; 311 while ((value = _tlv16_get_next(ptr, end, &type, &length, &ptr)) != NULL) 312 { 313 if (type == desired_type) 314 { 315 _assign_null_safe(out_length, length); 316 _assign_null_safe(out_ptr, ptr); 317 break; 318 } 319 } 320 return value; 321 } 322 323 const uint8_t *get_tlv(const uint8_t *const start, const uint8_t *const end, const uint16_t type, size_t *const out_length) 324 { 325 return _tlv16_get_value(start, end, type, out_length, NULL); 326 } 327 328 const char *get_tlv_string(const uint8_t *const start, const uint8_t *const end, const uint16_t type) 329 { 330 const char *str_value = NULL; 331 size_t length; 332 const char *value = (const char *)_tlv16_get_value(start, end, type, &length, NULL); 333 if(strnlen(value, length) == (length - 1)) 334 { 335 str_value = value; 336 } 337 return str_value; 338 } 339 340 uint32_t get_tlv_uint32(const uint8_t *const start, const uint8_t *const end, const uint16_t type, int *const out_error) 341 { 342 size_t length; 343 const uint8_t *value; 344 int err = -1; 345 uint32_t u32 = 0; 346 if ((value = _tlv16_get_value(start, end, type, &length, NULL)) != NULL) 347 { 348 switch (length) 349 { 350 case 1: 351 u32 = *value; 352 err = 0; 353 break; 354 case 2: 355 u32 = _read_big16(value, NULL); 356 err = 0; 357 break; 358 case 4: 359 u32 = _read_big32(value, NULL); 360 err = 0; 361 break; 362 default: 363 break; 364 } 365 } 366 _assign_null_safe(out_error, err); 367 return u32; 368 } 369 370 const uint8_t *get_tlv_uuid(const uint8_t *const start, const uint8_t *const end, const uint16_t type) 371 { 372 const uint8_t *uuid = NULL; 373 size_t length = 0; 374 const uint8_t *const value = get_tlv(start, end, type, &length); 375 mdns_require_quiet(value, exit); 376 mdns_require_quiet(length == MDNS_UUID_SIZE, exit); 377 378 uuid = value; 379 380 exit: 381 return uuid; 382 } 383 384 void ConvertHeaderBytes(ipc_msg_hdr *hdr) 385 { 386 hdr->version = htonl(hdr->version); 387 hdr->datalen = htonl(hdr->datalen); 388 hdr->ipc_flags = htonl(hdr->ipc_flags); 389 hdr->op = htonl(hdr->op ); 390 hdr->reg_index = htonl(hdr->reg_index); 391 } 392