1/* 2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This ds contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this ds except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * ds. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#ifdef DS_AVAILABLE 25 26#include <stdio.h> 27#include <stdlib.h> 28#include <unistd.h> 29#include <string.h> 30#include <time.h> 31#include <errno.h> 32#include <arpa/inet.h> 33#include <sys/stat.h> 34#include <pthread.h> 35#include <ils.h> 36#include <pwd.h> 37#include <grp.h> 38#include <fstab.h> 39#include <netdb.h> 40#include <notify.h> 41#include <notify_keys.h> 42#include <si_data.h> 43#include <si_module.h> 44#include <netdb_async.h> 45#include <net/if.h> 46#include <xpc/xpc.h> 47#include <xpc/private.h> 48#include <opendirectory/odipc.h> 49#include <servers/bootstrap.h> 50#include <bootstrap_priv.h> 51#include <opendirectory/DSlibinfoMIG_types.h> 52#ifdef DEBUG 53#include <asl.h> 54#endif 55 56#define IPV6_ADDR_LEN 16 57#define IPV4_ADDR_LEN 4 58 59typedef si_item_t *(*od_extract_t)(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat); 60 61/* notify SPI */ 62uint32_t notify_peek(int token, uint32_t *val); 63 64typedef struct 65{ 66 int notify_token_global; 67 int notify_token_user; 68 int notify_token_group; 69 int notify_token_service; 70} ds_si_private_t; 71 72extern uint32_t gL1CacheEnabled; 73extern int _si_opendirectory_disabled; 74 75static pthread_key_t _ds_serv_cache_key = 0; 76static xpc_pipe_t __od_pipe; /* use accessor only */ 77static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 78 79mach_port_t _ds_port; 80 81static void 82_od_fork_child(void) 83{ 84 // re-enable opendirectory interaction since we forked 85 _si_opendirectory_disabled = 0; 86 87 if (__od_pipe != NULL) { 88 xpc_pipe_invalidate(__od_pipe); 89 /* disable release due to 10649340, it will cause a minor leak for each fork without exec */ 90 // xpc_release(__od_pipe); 91 __od_pipe = NULL; 92 } 93 _ds_port = MACH_PORT_NULL; 94 pthread_mutex_unlock(&mutex); 95} 96 97static void 98_od_fork_prepare(void) 99{ 100 pthread_mutex_lock(&mutex); 101} 102 103static void 104_od_fork_parent(void) 105{ 106 pthread_mutex_unlock(&mutex); 107} 108 109static void 110_ds_serv_cache_free(void *x) 111{ 112 if (x != NULL) si_item_release(x); 113} 114 115void 116_si_disable_opendirectory(void) 117{ 118 _si_opendirectory_disabled = 1; 119 _ds_port = MACH_PORT_NULL; 120} 121 122XPC_RETURNS_RETAINED 123static xpc_pipe_t 124_od_xpc_pipe(bool resetPipe) 125{ 126 static dispatch_once_t once; 127 xpc_pipe_t result = NULL; 128 129 dispatch_once(&once, ^(void) { 130 char *xbs_disable; 131 132 /* if this is a build environment we ignore opendirectoryd */ 133 xbs_disable = getenv("XBS_DISABLE_LIBINFO"); 134 if ((issetugid() == 0) && (xbs_disable != NULL) && (strcmp(xbs_disable, "YES") == 0)) { 135 _si_opendirectory_disabled = 1; 136 return; 137 } 138 139 pthread_atfork(_od_fork_prepare, _od_fork_parent, _od_fork_child); 140 }); 141 142 if (_si_opendirectory_disabled == 1) { 143 return NULL; 144 } 145 146 pthread_mutex_lock(&mutex); 147 if (resetPipe) { 148 xpc_release(__od_pipe); 149 __od_pipe = NULL; 150 } 151 152 if (__od_pipe == NULL) { 153 if (!issetugid() && getenv("OD_DEBUG_MODE") != NULL) { 154 __od_pipe = xpc_pipe_create(kODMachLibinfoPortNameDebug, 0); 155 } else { 156 __od_pipe = xpc_pipe_create(kODMachLibinfoPortName, XPC_PIPE_FLAG_PRIVILEGED); 157 } 158 } 159 160 if (__od_pipe != NULL) result = xpc_retain(__od_pipe); 161 pthread_mutex_unlock(&mutex); 162 163 return result; 164} 165 166static bool 167_od_running(void) 168{ 169 xpc_pipe_t pipe; 170 171 pipe = _od_xpc_pipe(false); 172 if (pipe != NULL) { 173 xpc_release(pipe); 174 } 175 176 if (_si_opendirectory_disabled) { 177 return 0; 178 } 179 180 return (pipe != NULL); 181} 182 183static void 184_ds_child(void) 185{ 186 _ds_port = MACH_PORT_NULL; 187} 188 189int 190_ds_running(void) 191{ 192 kern_return_t status; 193 char *od_debug_mode = NULL; 194 195 if (_ds_port != MACH_PORT_NULL) return 1; 196 197 if (_si_opendirectory_disabled) return 0; 198 pthread_atfork(NULL, NULL, _ds_child); 199 200 if (!issetugid()) { 201 od_debug_mode = getenv("OD_DEBUG_MODE"); 202 } 203 204 if (od_debug_mode) { 205 status = bootstrap_look_up(bootstrap_port, kDSStdMachDSLookupPortName "_debug", &_ds_port); 206 } else { 207 status = bootstrap_look_up2(bootstrap_port, kDSStdMachDSLookupPortName, &_ds_port, 0, BOOTSTRAP_PRIVILEGED_SERVER); 208 } 209 if ((status != BOOTSTRAP_SUCCESS) && (status != BOOTSTRAP_UNKNOWN_SERVICE)) _ds_port = MACH_PORT_NULL; 210 211 return (_ds_port != MACH_PORT_NULL); 212} 213 214static bool 215_valid_token(xpc_object_t reply) 216{ 217 audit_token_t token; 218 219 /* 220 * This should really call audit_token_to_au32, 221 * but that's in libbsm, not in a Libsystem library. 222 */ 223 xpc_dictionary_get_audit_token(reply, &token); 224 225 return ((uid_t) token.val[1] == 0); 226} 227 228static void 229_ds_get_validation(si_mod_t *si, uint64_t *a, uint64_t *b, int cat) 230{ 231 ds_si_private_t *pp; 232 uint32_t peek; 233 int status; 234 235 if (si == NULL) return; 236 237 pp = (ds_si_private_t *)si->private; 238 if (pp == NULL) return; 239 240 if (a != NULL) 241 { 242 *a = 0; 243 status = notify_peek(pp->notify_token_global, &peek); 244 if (status == NOTIFY_STATUS_OK) *a = ntohl(peek); 245 } 246 247 if (b != NULL) 248 { 249 *b = 0; 250 peek = 0; 251 status = NOTIFY_STATUS_FAILED; 252 253 if (cat == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &peek); 254 else if (cat == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &peek); 255 else if (cat == CATEGORY_GROUPLIST) status = notify_peek(pp->notify_token_group, &peek); 256 else if (cat == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &peek); 257 258 if (status == NOTIFY_STATUS_OK) *b = ntohl(peek); 259 } 260} 261 262XPC_RETURNS_RETAINED 263__private_extern__ xpc_object_t 264_od_rpc_call(const char *procname, xpc_object_t payload, xpc_pipe_t (*get_pipe)(bool)) 265{ 266 xpc_object_t result = NULL; 267 xpc_object_t reply; 268 xpc_pipe_t od_pipe; 269 int retries, rc; 270 271 od_pipe = get_pipe(false); 272 if (od_pipe == NULL) return NULL; 273 274 if (payload == NULL) { 275 payload = xpc_dictionary_create(NULL, NULL, 0); 276 } 277 278 // we nest it for backward compatibility so we can do independent submissions 279 xpc_dictionary_set_string(payload, OD_RPC_NAME, procname); 280 xpc_dictionary_set_int64(payload, OD_RPC_VERSION, 2); 281 282 for (retries = 0; od_pipe != NULL && retries < 2; retries++) { 283 rc = xpc_pipe_routine(od_pipe, payload, &reply); 284 switch (rc) { 285 case EPIPE: 286 xpc_release(od_pipe); 287 od_pipe = get_pipe(true); 288 break; 289 290 case EAGAIN: 291 /* just loop and try to send again */ 292 break; 293 294 case 0: 295 if (_valid_token(reply) == true) { 296 result = reply; 297 } 298 /* fall through since we got a valid response */ 299 300 default: 301 /* release and NULL the pipe it'll break the loop */ 302 xpc_release(od_pipe); 303 od_pipe = NULL; 304 break; 305 } 306 } 307 308 if (od_pipe != NULL) { 309 xpc_release(od_pipe); 310 } 311 312 return result; 313} 314 315static si_list_t * 316_ds_list(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract) 317{ 318 __block si_list_t *list; 319 uint64_t va, vb; 320 xpc_object_t reply, result; 321 322 if (procname == NULL) return NULL; 323 324 _ds_get_validation(si, &va, &vb, cat); 325 326 list = NULL; 327 reply = _od_rpc_call(procname, NULL, _od_xpc_pipe); 328 if (reply != NULL) { 329 result = xpc_dictionary_get_value(reply, OD_RPC_RESULT); 330 if (result != NULL && xpc_get_type(result) == XPC_TYPE_ARRAY) { 331 xpc_array_apply(result, ^bool(size_t index, xpc_object_t value) { 332 si_item_t *item = extract(si, value, extra, va, vb); 333 list = si_list_add(list, item); 334 si_item_release(item); 335 336 return true; 337 }); 338 } 339 340 xpc_release(reply); 341 } 342 343 return list; 344} 345 346static si_item_t * 347_ds_item(si_mod_t *si, int cat, const char *procname, const void *extra, od_extract_t extract, xpc_object_t payload) 348{ 349 xpc_object_t result; 350 uint64_t va, vb; 351 si_item_t *item = NULL; 352 353 if (procname == NULL) return NULL; 354 355 result = _od_rpc_call(procname, payload, _od_xpc_pipe); 356 if (result != NULL) { 357 _ds_get_validation(si, &va, &vb, cat); 358 if (xpc_dictionary_get_int64(result, OD_RPC_ERROR) == 0) { 359 item = extract(si, result, extra, va, vb); 360 } 361 362 xpc_release(result); 363 } 364 365 return item; 366} 367 368static int 369_ds_is_valid(si_mod_t *si, si_item_t *item) 370{ 371 si_mod_t *src; 372 ds_si_private_t *pp; 373 int status; 374 uint32_t oldval, newval; 375 376 if (si == NULL) return 0; 377 if (item == NULL) return 0; 378 if (si->name == NULL) return 0; 379 if (item->src == NULL) return 0; 380 381 pp = (ds_si_private_t *)si->private; 382 if (pp == NULL) return 0; 383 384 src = (si_mod_t *)item->src; 385 386 if (src->name == NULL) return 0; 387 if (string_not_equal(si->name, src->name)) return 0; 388 389 /* check global invalidation */ 390 oldval = item->validation_a; 391 newval = -1; 392 status = notify_peek(pp->notify_token_global, &newval); 393 if (status != NOTIFY_STATUS_OK) return 0; 394 395 newval = ntohl(newval); 396 if (oldval != newval) return 0; 397 398 oldval = item->validation_b; 399 newval = -1; 400 if (item->type == CATEGORY_USER) status = notify_peek(pp->notify_token_user, &newval); 401 else if (item->type == CATEGORY_GROUP) status = notify_peek(pp->notify_token_group, &newval); 402 else if (item->type == CATEGORY_SERVICE) status = notify_peek(pp->notify_token_service, &newval); 403 else return 0; 404 405 if (status != NOTIFY_STATUS_OK) return 0; 406 407 newval = ntohl(newval); 408 if (oldval != newval) return 0; 409 410 return 1; 411} 412 413static void 414_free_addr_list(char **l) 415{ 416 int i; 417 418 if (l == NULL) return; 419 for (i = 0; l[i] != NULL; i++) free(l[i]); 420 free(l); 421} 422 423/* map ipv4 addresses and append to v6 list */ 424static int 425_map_v4(char ***v6, uint32_t n6, char **v4, uint32_t n4) 426{ 427 struct in6_addr a6; 428 uint32_t i; 429 430 a6.__u6_addr.__u6_addr32[0] = 0x00000000; 431 a6.__u6_addr.__u6_addr32[1] = 0x00000000; 432 a6.__u6_addr.__u6_addr32[2] = htonl(0x0000ffff); 433 434 if (*v6 == NULL) 435 { 436 *v6 = (char **)calloc(n4 + 1, sizeof(char *)); 437 } 438 else 439 { 440 *v6 = (char **)reallocf(*v6, (n6 + n4 + 1) * sizeof(char *)); 441 } 442 443 if (*v6 == NULL) return -1; 444 445 for (i = 0; i < n4; i++) 446 { 447 (*v6)[n6] = (char *)calloc(1, IPV6_ADDR_LEN); 448 if ((*v6)[n6] == NULL) return -1; 449 450 memcpy(&(a6.__u6_addr.__u6_addr32[3]), v4[i], IPV4_ADDR_LEN); 451 memcpy((*v6)[n6], &(a6.__u6_addr.__u6_addr32[0]), IPV6_ADDR_LEN); 452 453 n6++; 454 } 455 456 return 0; 457} 458 459static xpc_object_t 460_xpc_query_key_string(const char *key, const char *value) 461{ 462 xpc_object_t payload; 463 464 if (value == NULL) return NULL; 465 466 payload = xpc_dictionary_create(NULL, NULL, 0); 467 if (payload == NULL) return NULL; 468 469 xpc_dictionary_set_string(payload, key, value); 470 471 return payload; 472} 473 474static xpc_object_t 475_xpc_query_key_id(const char *key, id_t idValue) 476{ 477 xpc_object_t payload; 478 479 payload = xpc_dictionary_create(NULL, NULL, 0); 480 if (payload == NULL) return NULL; 481 482 xpc_dictionary_set_int64(payload, key, idValue); 483 484 return payload; 485} 486 487static xpc_object_t 488_xpc_query_key_uuid(const char *key, uuid_t uu) 489{ 490 xpc_object_t payload; 491 492 payload = xpc_dictionary_create(NULL, NULL, 0); 493 if (payload == NULL) return NULL; 494 495 xpc_dictionary_set_uuid(payload, key, uu); 496 497 return payload; 498} 499 500static xpc_object_t 501_xpc_query_key_int(const char *key, int64_t intValue) 502{ 503 xpc_object_t payload; 504 505 payload = xpc_dictionary_create(NULL, NULL, 0); 506 if (payload == NULL) return NULL; 507 508 xpc_dictionary_set_int64(payload, key, intValue); 509 510 return payload; 511} 512 513#pragma mark - 514 515static int 516_extract_string_from_xpc_array_index(xpc_object_t reply, int index, const char **str) 517{ 518 xpc_object_t value; 519 520 if (xpc_array_get_count(reply) < index) return -1; 521 522 value = xpc_array_get_value(reply, index); 523 if (xpc_get_type(value) != XPC_TYPE_STRING) return -1; 524 525 *str = xpc_string_get_string_ptr(value); 526 return 0; 527} 528 529static int 530_extract_string_from_xpc_object(xpc_object_t value, const char **str) 531{ 532 if (value == NULL) return -1; 533 else if (xpc_get_type(value) == XPC_TYPE_STRING) 534 { 535 *str = xpc_string_get_string_ptr(value); 536 return 0; 537 } 538 else if (xpc_get_type(value) == XPC_TYPE_ARRAY) 539 { 540 return _extract_string_from_xpc_array_index(value, 0, str); 541 } 542 543 return -1; 544} 545 546static int 547_extract_uint32_from_xpc_object(xpc_object_t value, uint32_t *val32) 548{ 549 xpc_type_t type; 550 551 if (value == NULL) return -1; 552 type = xpc_get_type(value); 553 554 if (type == XPC_TYPE_STRING) 555 { 556 *val32 = atoi(xpc_string_get_string_ptr(value)); 557 return 0; 558 } 559 else if (type == XPC_TYPE_INT64) 560 { 561 *val32 = (uint32_t)xpc_int64_get_value(value); 562 return 0; 563 } 564 else if (type == XPC_TYPE_BOOL) 565 { 566 *val32 = (uint32_t)xpc_bool_get_value(value); 567 return 0; 568 } 569 else if (type == XPC_TYPE_ARRAY) 570 { 571 if (xpc_array_get_count(value) == 0) return -1; 572 return _extract_uint32_from_xpc_object(xpc_array_get_value(value, 0), val32); 573 } 574 575 return -1; 576} 577 578static int 579_extract_string_list_from_xpc_array_index(xpc_object_t reply, int index, unsigned int *len, char ***list) 580{ 581 char **result; 582 xpc_object_t xpc_array = xpc_array_get_value(reply, index); 583 584 if ((xpc_array == NULL) || (xpc_get_type(xpc_array) != XPC_TYPE_ARRAY)) return -1; 585 586 result = calloc(xpc_array_get_count(xpc_array) + 1, sizeof(*result)); 587 if (result == NULL) return -1; 588 589 /* include trailing NULL */ 590 if (len != NULL) (*len) = xpc_array_get_count(xpc_array) + 1; 591 592 xpc_array_apply(xpc_array, ^bool(size_t idx, xpc_object_t value) { 593 result[idx] = (char *)xpc_string_get_string_ptr(value); 594 return true; 595 }); 596 597 *list = result; 598 return 0; 599} 600 601static int 602_extract_uint32_from_xpc_array_index(xpc_object_t reply, int index, uint32_t *val32) 603{ 604 xpc_object_t value = xpc_array_get_value(reply, index); 605 return _extract_uint32_from_xpc_object(value, val32); 606} 607 608static int 609_extract_string_list_from_xpc_array(xpc_object_t xpc_array, unsigned int *len, char ***list) 610{ 611 char **result; 612 613 if ((xpc_array == NULL) || (xpc_get_type(xpc_array) != XPC_TYPE_ARRAY)) return -1; 614 615 result = calloc(xpc_array_get_count(xpc_array) + 1, sizeof(*result)); 616 if (result == NULL) return -1; 617 618 /* include trailing NULL */ 619 if (len != NULL) (*len) = xpc_array_get_count(xpc_array) + 1; 620 621 xpc_array_apply(xpc_array, ^bool(size_t idx, xpc_object_t value) { 622 result[idx] = (char *)xpc_string_get_string_ptr(value); 623 return true; 624 }); 625 626 *list = result; 627 return 0; 628} 629 630static int 631_extract_string_from_xpc_dict(xpc_object_t reply, const char *key, const char **str) 632{ 633 xpc_object_t value = xpc_dictionary_get_value(reply, key); 634 const char *result; 635 636 if (value == NULL) return -1; 637 638 if (xpc_get_type(value) != XPC_TYPE_STRING) return -1; 639 640 result = xpc_string_get_string_ptr(value); 641 if (result == NULL) return -1; 642 643 *str = result; 644 return 0; 645} 646 647static int 648_extract_uint32_from_xpc_dict(xpc_object_t reply, const char *key, uint32_t *val32) 649{ 650 xpc_object_t value = xpc_dictionary_get_value(reply, key); 651 return _extract_uint32_from_xpc_object(value, val32); 652} 653 654#pragma mark - 655 656/* 657 * user schema 658 * 659 * name : string 660 * passwd : string 661 * uid : uint32 662 * gid : uint32 663 * gecos : string 664 * dir : string 665 * shell : string 666 */ 667 668static si_item_t * 669_extract_user_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 670{ 671 struct passwd tmp; 672 int i = 0; 673 674 if (xpc_array_get_count(reply) < 7) return NULL; 675 676 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.pw_name)) return NULL; 677 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.pw_passwd)) return NULL; 678 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.pw_uid)) return NULL; 679 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.pw_gid)) return NULL; 680 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.pw_gecos)) return NULL; 681 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.pw_dir)) return NULL; 682 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.pw_shell)) return NULL; 683 684 /* default values */ 685 tmp.pw_change = (time_t)0; 686 tmp.pw_expire = (time_t)0; 687 tmp.pw_class = (char *)""; 688 689 return (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, valid_global, valid_cat, tmp.pw_name, tmp.pw_passwd, tmp.pw_uid, tmp.pw_gid, tmp.pw_change, tmp.pw_class, tmp.pw_gecos, tmp.pw_dir, tmp.pw_shell, tmp.pw_expire); 690} 691 692static si_item_t * 693_extract_user_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 694{ 695 __block struct passwd tmp; 696 __block int status = 0; 697 __block int parts = 3; 698 699 tmp.pw_name = (char *)""; 700 tmp.pw_passwd = (char *)"*"; 701 tmp.pw_uid = (uid_t)0; 702 tmp.pw_gid = (gid_t)0; 703 tmp.pw_change = (time_t)0; 704 tmp.pw_expire = (time_t)0; 705 tmp.pw_class = (char *)""; 706 tmp.pw_gecos = (char *)""; 707 tmp.pw_dir = (char *)"/var/empty"; 708 tmp.pw_shell = (char *)"/usr/bin/false"; 709 710 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 711 if (key == NULL) return true; 712 else if (!strcmp(key, "pw_name")) 713 { 714 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_name); 715 if (status == 0) parts--; 716 } 717 else if (!strcmp(key, "pw_passwd")) 718 { 719 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_passwd); 720 /* no parts check - this value is optional */ 721 } 722 else if (!strcmp(key, "pw_uid")) 723 { 724 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_uid); 725 if (status == 0) parts--; 726 } 727 else if (!strcmp(key, "pw_gid")) 728 { 729 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_gid); 730 if (status == 0) parts--; 731 } 732 else if (!strcmp(key, "pw_change")) 733 { 734 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_change); 735 /* no parts check - this value is optional */ 736 } 737 else if (!strcmp(key, "pw_expire")) 738 { 739 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.pw_expire); 740 /* no parts check - this value is optional */ 741 } 742 else if (!strcmp(key, "pw_class")) 743 { 744 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_class); 745 /* no parts check - this value is optional */ 746 } 747 else if (!strcmp(key, "pw_gecos")) 748 { 749 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_gecos); 750 /* no parts check - this value is optional */ 751 } 752 else if (!strcmp(key, "pw_dir")) 753 { 754 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_dir); 755 /* no parts check - this value is optional */ 756 } 757 else if (!strcmp(key, "pw_shell")) 758 { 759 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.pw_shell); 760 /* no parts check - this value is optional */ 761 } 762 return true; 763 }); 764 765 if ((status != 0) || (parts != 0)) return NULL; 766 767 return (si_item_t *)LI_ils_create("L4488ss44LssssL", (unsigned long)si, CATEGORY_USER, 1, valid_global, valid_cat, tmp.pw_name, tmp.pw_passwd, tmp.pw_uid, tmp.pw_gid, tmp.pw_change, tmp.pw_class, tmp.pw_gecos, tmp.pw_dir, tmp.pw_shell, tmp.pw_expire); 768} 769 770static si_item_t * 771_extract_user(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 772{ 773 xpc_type_t type; 774 775 if (si == NULL) return NULL; 776 if (reply == NULL) return NULL; 777 778 type = xpc_get_type(reply); 779 780 if (type == XPC_TYPE_ARRAY) return _extract_user_array(si, reply, valid_global, valid_cat); 781 else if (type == XPC_TYPE_DICTIONARY) return _extract_user_dict(si, reply, valid_global, valid_cat); 782 783 return NULL; 784} 785 786/* 787 * group schema 788 * 789 * name : string 790 * gid : uint32 791 * optional members : array of string 792 * 793 */ 794 795static si_item_t * 796_extract_group_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 797{ 798 si_item_t *item; 799 struct group tmp; 800 int i = 0; 801 int arraycount = xpc_array_get_count(reply); 802 803 if ((arraycount < 2) || (arraycount > 3)) return NULL; 804 805 memset(&tmp, 0, sizeof(tmp)); 806 807 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.gr_name)) return NULL; 808 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.gr_gid)) return NULL; 809 810 if (arraycount == 3) 811 { 812 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.gr_mem)) return NULL; 813 } 814 815 /* default value */ 816 tmp.gr_passwd = (char *)"*"; 817 818 item = (si_item_t *) LI_ils_create("L4488ss4*", (unsigned long)si, CATEGORY_GROUP, 1, valid_global, valid_cat, tmp.gr_name, tmp.gr_passwd, tmp.gr_gid, tmp.gr_mem); 819 820 free(tmp.gr_mem); 821 822 return item; 823} 824 825static si_item_t * 826_extract_group_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 827{ 828 si_item_t *item; 829 __block struct group tmp; 830 __block int status = 0; 831 __block int parts = 2; 832 833 tmp.gr_name = (char *)""; 834 tmp.gr_passwd = (char *)"*"; 835 tmp.gr_gid = (gid_t)0; 836 tmp.gr_mem = NULL; 837 838 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 839 if (key == NULL) return true; 840 else if (!strcmp(key, "gr_name")) 841 { 842 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.gr_name); 843 if (status == 0) parts--; 844 } 845 else if (!strcmp(key, "gr_passwd")) 846 { 847 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.gr_passwd); 848 /* no parts check - this value is optional */ 849 } 850 else if (!strcmp(key, "gr_gid")) 851 { 852 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.gr_gid); 853 if (status == 0) parts--; 854 } 855 else if (!strcmp(key, "gr_mem")) 856 { 857 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.gr_mem); 858 /* no parts check - this value is optional */ 859 } 860 return true; 861 }); 862 863 if ((status != 0) || (parts != 0)) 864 { 865 free(tmp.gr_mem); 866 return NULL; 867 } 868 869 item = (si_item_t *) LI_ils_create("L4488ss4*", (unsigned long)si, CATEGORY_GROUP, 1, valid_global, valid_cat, tmp.gr_name, tmp.gr_passwd, tmp.gr_gid, tmp.gr_mem); 870 871 free(tmp.gr_mem); 872 873 return item; 874} 875 876static si_item_t * 877_extract_group(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 878{ 879 xpc_type_t type; 880 881 if (si == NULL) return NULL; 882 if (reply == NULL) return NULL; 883 884 type = xpc_get_type(reply); 885 if (type == XPC_TYPE_ARRAY) return _extract_group_array(si, reply, valid_global, valid_cat); 886 else if (type == XPC_TYPE_DICTIONARY) return _extract_group_dict(si, reply, valid_global, valid_cat); 887 888 return NULL; 889} 890 891/* 892 * netgroup schema 893 * 894 * host : string 895 * user : string 896 * domain : string 897 * 898 */ 899static si_item_t * 900_extract_netgroup_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 901{ 902 const char *host, *user, *domain; 903 int i = 0; 904 905 if (xpc_array_get_count(reply) != 3) return NULL; 906 907 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&host)) return NULL; 908 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&user)) return NULL; 909 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&domain)) return NULL; 910 911 return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, valid_global, valid_cat, host, user, domain); 912} 913 914static si_item_t * 915_extract_netgroup_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 916{ 917 __block const char *host = ""; 918 __block const char *user = ""; 919 __block const char *domain = ""; 920 __block int status = 0; 921 __block int parts = 3; 922 923 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 924 if (key == NULL) return true; 925 else if (!strcmp(key, "host")) 926 { 927 status |= _extract_string_from_xpc_object(value, (const char **)&host); 928 if (status == 0) parts--; 929 } 930 else if (!strcmp(key, "user")) 931 { 932 status |= _extract_string_from_xpc_object(value, (const char **)&user); 933 if (status == 0) parts--; 934 } 935 else if (!strcmp(key, "domain")) 936 { 937 status |= _extract_string_from_xpc_object(value, (const char **)&domain); 938 if (status == 0) parts--; 939 } 940 return true; 941 }); 942 943 if ((status != 0) || (parts != 0)) return NULL; 944 945 return (si_item_t *)LI_ils_create("L4488sss", (unsigned long)si, CATEGORY_NETGROUP, 1, valid_global, valid_cat, host, user, domain); 946} 947 948static si_item_t * 949_extract_netgroup(si_mod_t *si, xpc_object_t reply, const void *ignored, uint64_t valid_global, uint64_t valid_cat) 950{ 951 xpc_type_t type; 952 953 if (si == NULL) return NULL; 954 if (reply == NULL) return NULL; 955 956 type = xpc_get_type(reply); 957 if (type == XPC_TYPE_ARRAY) return _extract_netgroup_array(si, reply, valid_global, valid_cat); 958 else if (type == XPC_TYPE_DICTIONARY) return _extract_netgroup_dict(si, reply, valid_global, valid_cat); 959 960 return NULL; 961} 962 963/* 964 * alias schema 965 * 966 * name : string 967 * local : uint32 968 * optional members : array of string 969 * 970 */ 971 972static si_item_t * 973_extract_alias_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 974{ 975 si_item_t *item; 976 struct aliasent tmp; 977 int i = 0; 978 int arraycount = xpc_array_get_count(reply); 979 980 if ((arraycount < 2) || (arraycount > 3)) return NULL; 981 982 memset(&tmp, 0, sizeof(tmp)); 983 984 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.alias_name)) return NULL; 985 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.alias_local)) return NULL; 986 987 if (arraycount == 3) 988 { 989 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.alias_members)) return NULL; 990 } 991 992 item = (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, valid_global, valid_cat, tmp.alias_name, tmp.alias_members_len, tmp.alias_members, tmp.alias_local); 993 994 free(tmp.alias_members); 995 996 return item; 997} 998 999static si_item_t * 1000_extract_alias_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1001{ 1002 si_item_t *item; 1003 __block struct aliasent tmp; 1004 __block int status = 0; 1005 __block int parts = 2; 1006 1007 tmp.alias_name = (char *)""; 1008 tmp.alias_local = 0; 1009 tmp.alias_members = NULL; 1010 tmp.alias_members_len = 0; 1011 1012 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 1013 if (key == NULL) return true; 1014 else if (!strcmp(key, "alias_name")) 1015 { 1016 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.alias_name); 1017 if (status == 0) parts--; 1018 } 1019 else if (!strcmp(key, "alias_local")) 1020 { 1021 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.alias_local); 1022 if (status == 0) parts--; 1023 } 1024 else if (!strcmp(key, "alias_members")) 1025 { 1026 status |= _extract_string_list_from_xpc_array(value, &tmp.alias_members_len, (char ***)&tmp.alias_members); 1027 /* no parts check - this value is optional */ 1028 } 1029 return true; 1030 }); 1031 1032 if ((status != 0) || (parts != 0)) 1033 { 1034 free(tmp.alias_members); 1035 return NULL; 1036 } 1037 1038 item = (si_item_t *)LI_ils_create("L4488s4*4", (unsigned long)si, CATEGORY_ALIAS, 1, valid_global, valid_cat, tmp.alias_name, tmp.alias_members_len, tmp.alias_members, tmp.alias_local); 1039 1040 free(tmp.alias_members); 1041 1042 return item; 1043} 1044 1045static si_item_t * 1046_extract_alias(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 1047{ 1048 xpc_type_t type; 1049 1050 if (si == NULL) return NULL; 1051 if (reply == NULL) return NULL; 1052 1053 type = xpc_get_type(reply); 1054 if (type == XPC_TYPE_ARRAY) return _extract_alias_array(si, reply, valid_global, valid_cat); 1055 else if (type == XPC_TYPE_DICTIONARY) return _extract_alias_dict(si, reply, valid_global, valid_cat); 1056 1057 return NULL; 1058} 1059 1060/* 1061 * network schema 1062 * 1063 * name : string 1064 * net : uint32 1065 * optional aliases : array of string 1066 * 1067 */ 1068 1069static si_item_t * 1070_extract_network_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1071{ 1072 si_item_t *item; 1073 struct netent tmp; 1074 int i = 0; 1075 int arraycount = xpc_array_get_count(reply); 1076 1077 if ((arraycount < 2) || (arraycount > 3)) return NULL; 1078 1079 memset(&tmp, 0, sizeof(tmp)); 1080 1081 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.n_name)) return NULL; 1082 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.n_net)) return NULL; 1083 1084 if (arraycount == 3) 1085 { 1086 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.n_aliases)) return NULL; 1087 } 1088 1089 /* default value */ 1090 tmp.n_addrtype = AF_INET; 1091 1092 item = (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, CATEGORY_NETWORK, 1, valid_global, valid_cat, tmp.n_name, tmp.n_aliases, tmp.n_addrtype, tmp.n_net); 1093 1094 free(tmp.n_aliases); 1095 1096 return item; 1097} 1098 1099static si_item_t * 1100_extract_network_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1101{ 1102 si_item_t *item; 1103 __block struct netent tmp; 1104 __block int status = 0; 1105 __block int parts = 2; 1106 1107 if (si == NULL) return NULL; 1108 if (reply == NULL) return NULL; 1109 1110 tmp.n_name = (char *)""; 1111 tmp.n_aliases = NULL; 1112 tmp.n_net = 0; 1113 1114 /* default value */ 1115 tmp.n_addrtype = AF_INET; 1116 1117 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 1118 if (key == NULL) return true; 1119 else if (!strcmp(key, "n_name")) 1120 { 1121 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.n_name); 1122 if (status == 0) parts--; 1123 } 1124 else if (!strcmp(key, "n_aliases")) 1125 { 1126 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.n_aliases); 1127 /* no parts check - this value is optional */ 1128 } 1129 else if (!strcmp(key, "n_net")) 1130 { 1131 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.n_net); 1132 if (status == 0) parts--; 1133 } 1134 return true; 1135 }); 1136 1137 if ((status != 0) || (parts != 0)) 1138 { 1139 free(tmp.n_aliases); 1140 return NULL; 1141 } 1142 1143 item = (si_item_t *)LI_ils_create("L4488s*44", (unsigned long)si, CATEGORY_NETWORK, 1, valid_global, valid_cat, tmp.n_name, tmp.n_aliases, tmp.n_addrtype, tmp.n_net); 1144 1145 free(tmp.n_aliases); 1146 1147 return item; 1148} 1149 1150static si_item_t * 1151_extract_network(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 1152{ 1153 xpc_type_t type; 1154 1155 if (si == NULL) return NULL; 1156 if (reply == NULL) return NULL; 1157 1158 type = xpc_get_type(reply); 1159 if (type == XPC_TYPE_ARRAY) return _extract_network_array(si, reply, valid_global, valid_cat); 1160 else if (type == XPC_TYPE_DICTIONARY) return _extract_network_dict(si, reply, valid_global, valid_cat); 1161 1162 return NULL; 1163} 1164 1165/* 1166 * service schema 1167 * 1168 * name : string 1169 * port : uint32 1170 * proto : string 1171 * optional aliases : array of string 1172 * 1173 */ 1174 1175static si_item_t * 1176_extract_service_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1177{ 1178 si_item_t *item; 1179 struct servent tmp; 1180 int i = 0; 1181 int arraycount = xpc_array_get_count(reply); 1182 1183 if ((arraycount < 3) || (arraycount > 4)) return NULL; 1184 1185 memset(&tmp, 0, sizeof(tmp)); 1186 1187 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.s_name)) return NULL; 1188 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.s_port)) return NULL; 1189 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.s_proto)) return NULL; 1190 1191 if (arraycount == 4) 1192 { 1193 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.s_aliases)) return NULL; 1194 } 1195 1196 item = (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, valid_global, valid_cat, tmp.s_name, tmp.s_aliases, tmp.s_port, tmp.s_proto); 1197 1198 free(tmp.s_aliases); 1199 1200 return item; 1201} 1202 1203static si_item_t * 1204_extract_service_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1205{ 1206 si_item_t *item; 1207 __block struct servent tmp; 1208 __block int status = 0; 1209 __block int parts = 3; 1210 1211 if (si == NULL) return NULL; 1212 if (reply == NULL) return NULL; 1213 1214 tmp.s_name = (char *)""; 1215 tmp.s_aliases = NULL; 1216 tmp.s_port = 0; 1217 tmp.s_proto = (char *)""; 1218 1219 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 1220 if (key == NULL) return true; 1221 else if (!strcmp(key, "s_name")) 1222 { 1223 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.s_name); 1224 if (status == 0) parts--; 1225 } 1226 else if (!strcmp(key, "s_aliases")) 1227 { 1228 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.s_aliases); 1229 /* no parts check - this value is optional */ 1230 } 1231 else if (!strcmp(key, "s_port")) 1232 { 1233 uint32_t v32; 1234 status |= _extract_uint32_from_xpc_object(value, &v32); 1235 if (status == 0) 1236 { 1237 tmp.s_port = (unsigned int)htons(v32); // ugh 1238 parts--; 1239 } 1240 } 1241 else if (!strcmp(key, "s_proto")) 1242 { 1243 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.s_proto); 1244 if (status == 0) parts--; 1245 } 1246 return true; 1247 }); 1248 1249 if ((status != 0) || (parts != 0)) 1250 { 1251 free(tmp.s_aliases); 1252 return NULL; 1253 } 1254 1255 item = (si_item_t *)LI_ils_create("L4488s*4s", (unsigned long)si, CATEGORY_SERVICE, 1, valid_global, valid_cat, tmp.s_name, tmp.s_aliases, tmp.s_port, tmp.s_proto); 1256 1257 free(tmp.s_aliases); 1258 1259 return item; 1260} 1261 1262static si_item_t * 1263_extract_service(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 1264{ 1265 xpc_type_t type; 1266 1267 if (si == NULL) return NULL; 1268 if (reply == NULL) return NULL; 1269 1270 type = xpc_get_type(reply); 1271 if (type == XPC_TYPE_ARRAY) return _extract_service_array(si, reply, valid_global, valid_cat); 1272 else if (type == XPC_TYPE_DICTIONARY) return _extract_service_dict(si, reply, valid_global, valid_cat); 1273 1274 return NULL; 1275} 1276 1277/* 1278 * protocol schema 1279 * 1280 * name : string 1281 * proto : uint32 1282 * optional aliases : array of string 1283 * 1284 */ 1285static si_item_t * 1286_extract_protocol_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1287{ 1288 si_item_t *item; 1289 struct protoent tmp; 1290 int i = 0; 1291 int arraycount = xpc_array_get_count(reply); 1292 1293 if ((arraycount < 2) || (arraycount > 3)) return NULL; 1294 1295 memset(&tmp, 0, sizeof(tmp)); 1296 1297 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.p_name)) return NULL; 1298 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.p_proto)) return NULL; 1299 1300 if (arraycount == 3) 1301 { 1302 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.p_aliases)) return NULL; 1303 } 1304 1305 item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_PROTOCOL, 1, valid_global, valid_cat, tmp.p_name, tmp.p_aliases, tmp.p_proto); 1306 1307 free(tmp.p_aliases); 1308 1309 return item; 1310} 1311 1312static si_item_t * 1313_extract_protocol_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1314{ 1315 si_item_t *item; 1316 __block struct protoent tmp; 1317 __block int status = 0; 1318 __block int parts = 2; 1319 1320 tmp.p_name = (char *)""; 1321 tmp.p_proto = 0; 1322 tmp.p_aliases = NULL; 1323 1324 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 1325 if (key == NULL) return true; 1326 else if (!strcmp(key, "p_name")) 1327 { 1328 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.p_name); 1329 if (status == 0) parts--; 1330 } 1331 else if (!strcmp(key, "p_proto")) 1332 { 1333 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.p_proto); 1334 if (status == 0) parts--; 1335 } 1336 else if (!strcmp(key, "p_aliases")) 1337 { 1338 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.p_aliases); 1339 /* no parts check - this value is optional */ 1340 } 1341 return true; 1342 }); 1343 1344 if ((status != 0) || (parts != 0)) 1345 { 1346 free(tmp.p_aliases); 1347 return NULL; 1348 } 1349 1350 item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_PROTOCOL, 1, valid_global, valid_cat, tmp.p_name, tmp.p_aliases, tmp.p_proto); 1351 1352 free(tmp.p_aliases); 1353 1354 return item; 1355} 1356 1357static si_item_t * 1358_extract_protocol(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 1359{ 1360 xpc_type_t type; 1361 1362 if (si == NULL) return NULL; 1363 if (reply == NULL) return NULL; 1364 1365 type = xpc_get_type(reply); 1366 if (type == XPC_TYPE_ARRAY) return _extract_protocol_array(si, reply, valid_global, valid_cat); 1367 else if (type == XPC_TYPE_DICTIONARY) return _extract_protocol_dict(si, reply, valid_global, valid_cat); 1368 1369 return NULL; 1370} 1371 1372/* 1373 * rpc schema 1374 * 1375 * name : string 1376 * number : uint32 1377 * optional aliases : array of string 1378 * 1379 */ 1380 1381static si_item_t * 1382_extract_rpc_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1383{ 1384 si_item_t *item; 1385 struct rpcent tmp; 1386 int i = 0; 1387 int arraycount = xpc_array_get_count(reply); 1388 1389 if ((arraycount < 2) || (arraycount > 3)) return NULL; 1390 1391 memset(&tmp, 0, sizeof(tmp)); 1392 1393 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.r_name)) return NULL; 1394 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.r_number)) return NULL; 1395 1396 if (arraycount == 3) 1397 { 1398 if (0 != _extract_string_list_from_xpc_array_index(reply, i++, NULL, (char ***)&tmp.r_aliases)) return NULL; 1399 } 1400 1401 item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_RPC, 1, valid_global, valid_cat, tmp.r_name, tmp.r_aliases, tmp.r_number); 1402 1403 free(tmp.r_aliases); 1404 1405 return item; 1406} 1407 1408static si_item_t * 1409_extract_rpc_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1410{ 1411 si_item_t *item; 1412 __block struct rpcent tmp; 1413 __block int status = 0; 1414 __block int parts = 2; 1415 1416 tmp.r_name = (char *)""; 1417 tmp.r_number = 0; 1418 tmp.r_aliases = NULL; 1419 1420 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 1421 if (key == NULL) return true; 1422 else if (!strcmp(key, "r_name")) 1423 { 1424 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.r_name); 1425 if (status == 0) parts--; 1426 } 1427 else if (!strcmp(key, "r_number")) 1428 { 1429 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.r_number); 1430 if (status == 0) parts--; 1431 } 1432 else if (!strcmp(key, "r_aliases")) 1433 { 1434 status |= _extract_string_list_from_xpc_array(value, NULL, (char ***)&tmp.r_aliases); 1435 /* no parts check - this value is optional */ 1436 } 1437 return true; 1438 }); 1439 1440 if ((status != 0) || (parts != 0)) 1441 { 1442 free(tmp.r_aliases); 1443 return NULL; 1444 } 1445 1446 item = (si_item_t *)LI_ils_create("L4488s*4", (unsigned long)si, CATEGORY_RPC, 1, valid_global, valid_cat, tmp.r_name, tmp.r_aliases, tmp.r_number); 1447 1448 free(tmp.r_aliases); 1449 1450 return item; 1451} 1452 1453static si_item_t * 1454_extract_rpc(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 1455{ 1456 xpc_type_t type; 1457 1458 if (si == NULL) return NULL; 1459 if (reply == NULL) return NULL; 1460 1461 type = xpc_get_type(reply); 1462 if (type == XPC_TYPE_ARRAY) return _extract_rpc_array(si, reply, valid_global, valid_cat); 1463 else if (type == XPC_TYPE_DICTIONARY) return _extract_rpc_dict(si, reply, valid_global, valid_cat); 1464 1465 return NULL; 1466} 1467 1468/* 1469 * fstab schema 1470 * 1471 * file : string 1472 * spec : string 1473 * freq : uint32 1474 * passno : uint32 1475 * mntopts : string 1476 * type : string 1477 * vfstype : string 1478 */ 1479 1480static si_item_t * 1481_extract_fstab_array(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1482{ 1483 __block struct fstab tmp; 1484 int i = 0; 1485 1486 if (xpc_array_get_count(reply) != 7) return NULL; 1487 1488 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.fs_file)) return NULL; 1489 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.fs_spec)) return NULL; 1490 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.fs_freq)) return NULL; 1491 if (0 != _extract_uint32_from_xpc_array_index(reply, i++, (uint32_t *)&tmp.fs_passno)) return NULL; 1492 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.fs_mntops)) return NULL; 1493 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.fs_type)) return NULL; 1494 if (0 != _extract_string_from_xpc_array_index(reply, i++, (const char **)&tmp.fs_vfstype)) return NULL; 1495 1496 return (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, valid_global, valid_cat, tmp.fs_spec, tmp.fs_file, tmp.fs_vfstype, tmp.fs_mntops, tmp.fs_type, tmp.fs_freq, tmp.fs_passno); 1497} 1498 1499static si_item_t * 1500_extract_fstab_dict(si_mod_t *si, xpc_object_t reply, uint64_t valid_global, uint64_t valid_cat) 1501{ 1502 __block struct fstab tmp; 1503 __block int status = 0; 1504 __block int parts = 7; 1505 1506 tmp.fs_file = NULL; 1507 tmp.fs_spec = (char *)""; 1508 tmp.fs_freq = 0; 1509 tmp.fs_passno = 0; 1510 tmp.fs_mntops = (char *)""; 1511 tmp.fs_type = (char *)""; 1512 tmp.fs_vfstype = (char *)""; 1513 1514 xpc_dictionary_apply(reply, ^bool(const char *key, xpc_object_t value) { 1515 if (key == NULL) return true; 1516 else if (!strcmp(key, "fs_file")) 1517 { 1518 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_file); 1519 if (status == 0) parts--; 1520 } 1521 else if (!strcmp(key, "fs_spec")) 1522 { 1523 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_spec); 1524 if (status == 0) parts--; 1525 } 1526 else if (!strcmp(key, "fs_freq")) 1527 { 1528 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.fs_freq); 1529 if (status == 0) parts--; 1530 } 1531 else if (!strcmp(key, "fs_passno")) 1532 { 1533 status |= _extract_uint32_from_xpc_object(value, (uint32_t *)&tmp.fs_passno); 1534 if (status == 0) parts--; 1535 } 1536 else if (!strcmp(key, "fs_mntops")) 1537 { 1538 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_mntops); 1539 if (status == 0) parts--; 1540 } 1541 else if (!strcmp(key, "fs_type")) 1542 { 1543 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_type); 1544 if (status == 0) parts--; 1545 } 1546 else if (!strcmp(key, "fs_vfstype")) 1547 { 1548 status |= _extract_string_from_xpc_object(value, (const char **)&tmp.fs_vfstype); 1549 if (status == 0) parts--; 1550 } 1551 return true; 1552 }); 1553 1554 if ((status != 0) || (parts != 0)) return NULL; 1555 1556 return (si_item_t *)LI_ils_create("L4488sssss44", (unsigned long)si, CATEGORY_FS, 1, valid_global, valid_cat, tmp.fs_spec, tmp.fs_file, tmp.fs_vfstype, tmp.fs_mntops, tmp.fs_type, tmp.fs_freq, tmp.fs_passno); 1557} 1558 1559static si_item_t * 1560_extract_fstab(si_mod_t *si, xpc_object_t reply, __unused const void *ignored, uint64_t valid_global, uint64_t valid_cat) 1561{ 1562 xpc_type_t type; 1563 1564 if (si == NULL) return NULL; 1565 if (reply == NULL) return NULL; 1566 1567 type = xpc_get_type(reply); 1568 if (type == XPC_TYPE_ARRAY) return _extract_fstab_array(si, reply, valid_global, valid_cat); 1569 else if (type == XPC_TYPE_DICTIONARY) return _extract_fstab_dict(si, reply, valid_global, valid_cat); 1570 1571 return NULL; 1572} 1573 1574static si_item_t * 1575_extract_mac_mac(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat) 1576{ 1577 xpc_type_t type; 1578 char *cmac; 1579 const char *value = NULL; 1580 si_item_t *out; 1581 1582 if (si == NULL) return NULL; 1583 if (reply == NULL) return NULL; 1584 if (extra == NULL) return NULL; 1585 1586 type = xpc_get_type(reply); 1587 if (type == XPC_TYPE_ARRAY) 1588 { 1589 if (xpc_array_get_count(reply) >= 1) 1590 { 1591 if (0 != _extract_string_from_xpc_array_index(reply, 0, (const char **)&value)) return NULL; 1592 } 1593 } 1594 else if (type == XPC_TYPE_DICTIONARY) 1595 { 1596 if (0 != _extract_string_from_xpc_dict(reply, "mac", &value)) return NULL; 1597 } 1598 1599 if (value == NULL || value[0] == '\0') return NULL; 1600 1601 cmac = si_standardize_mac_address(value); 1602 if (cmac == NULL) return NULL; 1603 1604 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, extra, cmac); 1605 1606 free(cmac); 1607 1608 return out; 1609} 1610 1611static si_item_t * 1612_extract_mac_name(si_mod_t *si, xpc_object_t reply, const void *extra, uint64_t valid_global, uint64_t valid_cat) 1613{ 1614 xpc_type_t type; 1615 const char *name = NULL; 1616 si_item_t *out; 1617 1618 if (si == NULL) return NULL; 1619 if (reply == NULL) return NULL; 1620 if (extra == NULL) return NULL; 1621 1622 type = xpc_get_type(reply); 1623 if (type == XPC_TYPE_ARRAY) 1624 { 1625 if (xpc_array_get_count(reply) >= 1) 1626 { 1627 if (0 != _extract_string_from_xpc_array_index(reply, 0, (const char **)&name )) return NULL; 1628 } 1629 } 1630 else if (type == XPC_TYPE_DICTIONARY) 1631 { 1632 if (0 != _extract_string_from_xpc_dict(reply, "name", &name)) return NULL; 1633 } 1634 1635 if (name == NULL) return NULL; 1636 1637 out = (si_item_t *)LI_ils_create("L4488ss", (unsigned long)si, CATEGORY_MAC, 1, valid_global, valid_cat, name, extra); 1638 1639 return out; 1640} 1641 1642#pragma mark - 1643 1644static si_item_t * 1645ds_user_byname(si_mod_t *si, const char *name) 1646{ 1647 xpc_object_t payload; 1648 si_item_t *item; 1649 1650 if (!_od_running()) return NULL; 1651 1652 payload = _xpc_query_key_string("name", name); 1653 if (payload == NULL) return NULL; 1654 1655 item = _ds_item(si, CATEGORY_USER, "getpwnam", NULL, _extract_user, payload); 1656 1657 xpc_release(payload); 1658 return item; 1659} 1660 1661static si_item_t * 1662ds_user_byuid(si_mod_t *si, uid_t uid) 1663{ 1664 xpc_object_t payload; 1665 si_item_t *item; 1666 1667 if (!_od_running()) return NULL; 1668 1669 payload = _xpc_query_key_id("uid", uid); 1670 if (payload == NULL) return NULL; 1671 1672 item = _ds_item(si, CATEGORY_USER, "getpwuid", NULL, _extract_user, payload); 1673 1674 xpc_release(payload); 1675 return item; 1676} 1677 1678static si_item_t * 1679ds_user_byuuid(si_mod_t *si, uuid_t uuid) 1680{ 1681 xpc_object_t payload; 1682 si_item_t *item; 1683 1684 if (!_od_running()) return NULL; 1685 1686 payload = _xpc_query_key_uuid("uuid", uuid); 1687 if (payload == NULL) return NULL; 1688 1689 item = _ds_item(si, CATEGORY_USER, "getpwuuid", NULL, _extract_user, payload); 1690 1691 xpc_release(payload); 1692 return item; 1693} 1694 1695static si_list_t * 1696ds_user_all(si_mod_t *si) 1697{ 1698 return _ds_list(si, CATEGORY_USER, "getpwent", NULL, _extract_user); 1699} 1700 1701static si_item_t * 1702ds_group_byname(si_mod_t *si, const char *name) 1703{ 1704 xpc_object_t payload; 1705 si_item_t *item; 1706 1707 if (!_od_running()) return NULL; 1708 1709 payload = _xpc_query_key_string("name", name); 1710 if (payload == NULL) return NULL; 1711 1712 item = _ds_item(si, CATEGORY_GROUP, "getgrnam", NULL, _extract_group, payload); 1713 1714 xpc_release(payload); 1715 return item; 1716} 1717 1718static si_item_t * 1719ds_group_bygid(si_mod_t *si, gid_t gid) 1720{ 1721 xpc_object_t payload; 1722 si_item_t *item; 1723 1724 if (!_od_running()) return NULL; 1725 1726 payload = _xpc_query_key_id("gid", gid); 1727 if (payload == NULL) return NULL; 1728 1729 item = _ds_item(si, CATEGORY_GROUP, "getgrgid", NULL, _extract_group, payload); 1730 1731 xpc_release(payload); 1732 return item; 1733} 1734 1735static si_item_t * 1736ds_group_byuuid(si_mod_t *si, uuid_t uuid) 1737{ 1738 xpc_object_t payload; 1739 si_item_t *item; 1740 1741 if (!_od_running()) return NULL; 1742 1743 payload = _xpc_query_key_uuid("uuid", uuid); 1744 if (payload == NULL) return NULL; 1745 1746 item = _ds_item(si, CATEGORY_GROUP, "getgruuid", NULL, _extract_group, payload); 1747 1748 xpc_release(payload); 1749 return item; 1750} 1751 1752static si_list_t * 1753ds_group_all(si_mod_t *si) 1754{ 1755 if (!_od_running()) return NULL; 1756 return _ds_list(si, CATEGORY_GROUP, "getgrent", NULL, _extract_group); 1757} 1758 1759static si_item_t * 1760ds_grouplist(si_mod_t *si, const char *name, uint32_t ngroups) 1761{ 1762 xpc_object_t payload, reply; 1763 si_item_t *item = NULL; 1764 1765 if (!_od_running()) return NULL; 1766 if (name == NULL) return NULL; 1767 1768 payload = xpc_dictionary_create(NULL, NULL, 0); 1769 if (payload == NULL) return NULL; 1770 1771 xpc_dictionary_set_string(payload, "name", name); 1772 xpc_dictionary_set_int64(payload, "ngroups", ngroups); 1773 1774 reply = _od_rpc_call("getgrouplist", payload, _od_xpc_pipe); 1775 if (reply != NULL) { 1776 size_t gidptrsz; 1777 const gid_t *gidptr = xpc_dictionary_get_data(reply, "groups", &gidptrsz); 1778 uint32_t count = 0; 1779 uint64_t va, vb; 1780 1781 _ds_get_validation(si, &va, &vb, CATEGORY_GROUPLIST); 1782 1783 /* see what we were sent */ 1784 if (0 == _extract_uint32_from_xpc_dict(reply, "count", &count)) 1785 { 1786 if (count != 0) 1787 { 1788 item = (si_item_t *)LI_ils_create("L4488s4@", (unsigned long)si, CATEGORY_GROUPLIST, 1, va, vb, name, count, 1789 gidptrsz, gidptr); 1790 } 1791 } 1792 1793 xpc_release(reply); 1794 } 1795 1796 xpc_release(payload); 1797 1798 return item; 1799} 1800 1801static si_list_t * 1802ds_netgroup_byname(si_mod_t *si, const char *name) 1803{ 1804 xpc_object_t payload; 1805 si_list_t *list = NULL; 1806 si_item_t *item; 1807 1808 if (!_od_running()) return NULL; 1809 1810 payload = _xpc_query_key_string("netgroup", name); 1811 if (payload == NULL) return NULL; 1812 1813 item = _ds_item(si, CATEGORY_NETGROUP, "getnetgrent", NULL, _extract_netgroup, payload); 1814 if (item != NULL) { 1815 list = si_list_add(list, item); 1816 si_item_release(item); 1817 } 1818 1819 xpc_release(payload); 1820 1821 return list; 1822} 1823 1824static int 1825ds_in_netgroup(si_mod_t *si, const char *group, const char *host, const char *user, const char *domain) 1826{ 1827 xpc_object_t payload, reply; 1828 int is_innetgr; 1829 1830 if (!_od_running()) return 0; 1831 1832 payload = xpc_dictionary_create(NULL, NULL, 0); 1833 if (payload == NULL) return 0; 1834 1835 xpc_dictionary_set_string(payload, "netgroup", (group ? group : "")); 1836 xpc_dictionary_set_string(payload, "host", (host ? host : "")); 1837 xpc_dictionary_set_string(payload, "user", (user ? user : "")); 1838 xpc_dictionary_set_string(payload, "domain", (domain ? domain : "")); 1839 1840 reply = _od_rpc_call("innetgr", payload, _od_xpc_pipe); 1841 if (reply != NULL) { 1842 is_innetgr = xpc_dictionary_get_bool(reply, OD_RPC_RESULT); 1843 xpc_release(reply); 1844 } else { 1845 is_innetgr = 0; 1846 } 1847 1848 xpc_release(payload); 1849 1850 return is_innetgr; 1851} 1852 1853static si_item_t * 1854ds_alias_byname(si_mod_t *si, const char *name) 1855{ 1856 xpc_object_t payload; 1857 si_item_t *item; 1858 1859 if (!_od_running()) return NULL; 1860 1861 payload = _xpc_query_key_string("name", name); 1862 if (payload == NULL) return NULL; 1863 1864 item = _ds_item(si, CATEGORY_ALIAS, "alias_getbyname", NULL, _extract_alias, payload); 1865 1866 xpc_release(payload); 1867 return item; 1868} 1869 1870static si_list_t * 1871ds_alias_all(si_mod_t *si) 1872{ 1873 if (!_od_running()) return NULL; 1874 return _ds_list(si, CATEGORY_ALIAS, "alias_getent", NULL, _extract_alias); 1875} 1876 1877static si_item_t * 1878ds_network_byname(si_mod_t *si, const char *name) 1879{ 1880 xpc_object_t payload; 1881 si_item_t *item; 1882 1883 if (!_od_running()) return NULL; 1884 1885 payload = _xpc_query_key_string("name", name); 1886 if (payload == NULL) return NULL; 1887 1888 item = _ds_item(si, CATEGORY_NETWORK, "getnetbyname", NULL, _extract_network, payload); 1889 1890 xpc_release(payload); 1891 return item; 1892} 1893 1894static si_item_t * 1895ds_network_byaddr(si_mod_t *si, uint32_t addr) 1896{ 1897 unsigned char f1, f2, f3; 1898 char val[64]; 1899 xpc_object_t payload; 1900 si_item_t *item; 1901 1902 if (!_od_running()) return NULL; 1903 1904 f1 = addr & 0xff; 1905 addr >>= 8; 1906 f2 = addr & 0xff; 1907 addr >>= 8; 1908 f3 = addr & 0xff; 1909 1910 if (f3 != 0) snprintf(val, sizeof(val), "%u.%u.%u", f3, f2, f1); 1911 else if (f2 != 0) snprintf(val, sizeof(val), "%u.%u", f2, f1); 1912 else snprintf(val, sizeof(val), "%u", f1); 1913 1914 payload = _xpc_query_key_string("net", val); 1915 if (payload == NULL) return NULL; 1916 1917 item = _ds_item(si, CATEGORY_NETWORK, "getnetbyaddr", NULL, _extract_network, payload); 1918 1919 xpc_release(payload); 1920 return item; 1921} 1922 1923static si_list_t * 1924ds_network_all(si_mod_t *si) 1925{ 1926 if (!_od_running()) return NULL; 1927 return _ds_list(si, CATEGORY_NETWORK, "getnetent", NULL, _extract_network); 1928} 1929 1930static si_item_t * 1931ds_service_byname(si_mod_t *si, const char *name, const char *proto) 1932{ 1933 xpc_object_t payload; 1934 si_item_t *item; 1935 struct servent *s; 1936 1937 if (!_od_running()) return NULL; 1938 if (name == NULL) name = ""; 1939 if (proto == NULL) proto = ""; 1940 1941 /* Check our local service cache (see ds_addrinfo). */ 1942 item = pthread_getspecific(_ds_serv_cache_key); 1943 if (item != NULL) 1944 { 1945 s = (struct servent *)((uintptr_t)item + sizeof(si_item_t)); 1946 if (string_equal(name, s->s_name)) return si_item_retain(item); 1947 } 1948 1949 payload = xpc_dictionary_create(NULL, NULL, 0); 1950 if (payload == NULL) return NULL; 1951 1952 xpc_dictionary_set_string(payload, "name", name); 1953 xpc_dictionary_set_string(payload, "proto", proto); 1954 1955 item = _ds_item(si, CATEGORY_SERVICE, "getservbyname", NULL, _extract_service, payload); 1956 1957 xpc_release(payload); 1958 1959 return item; 1960} 1961 1962static si_item_t * 1963ds_service_byport(si_mod_t *si, int port, const char *proto) 1964{ 1965 xpc_object_t payload; 1966 si_item_t *item; 1967 1968 if (!_od_running()) return NULL; 1969 1970 payload = xpc_dictionary_create(NULL, NULL, 0); 1971 if (payload == NULL) return NULL; 1972 1973 /* swap to native order, API passes network order */ 1974 xpc_dictionary_set_int64(payload, "port", ntohs(port)); 1975 xpc_dictionary_set_string(payload, "proto", (proto ? proto : "")); 1976 1977 item = _ds_item(si, CATEGORY_SERVICE, "getservbyport", NULL, _extract_service, payload); 1978 1979 xpc_release(payload); 1980 1981 return item; 1982} 1983 1984static si_list_t * 1985ds_service_all(si_mod_t *si) 1986{ 1987 if (!_od_running()) return NULL; 1988 return _ds_list(si, CATEGORY_SERVICE, "getservent", NULL, _extract_service); 1989} 1990 1991static si_item_t * 1992ds_protocol_byname(si_mod_t *si, const char *name) 1993{ 1994 xpc_object_t payload; 1995 si_item_t *item; 1996 1997 if (!_od_running()) return NULL; 1998 1999 payload = _xpc_query_key_string("name", name); 2000 if (payload == NULL) return NULL; 2001 2002 item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobyname", NULL, _extract_protocol, payload); 2003 2004 xpc_release(payload); 2005 return item; 2006} 2007 2008static si_item_t * 2009ds_protocol_bynumber(si_mod_t *si, int number) 2010{ 2011 xpc_object_t payload; 2012 si_item_t *item; 2013 2014 if (!_od_running()) return NULL; 2015 2016 payload = _xpc_query_key_int("number", number); 2017 if (payload == NULL) return NULL; 2018 2019 item = _ds_item(si, CATEGORY_PROTOCOL, "getprotobynumber", NULL, _extract_protocol, payload); 2020 2021 xpc_release(payload); 2022 return item; 2023} 2024 2025static si_list_t * 2026ds_protocol_all(si_mod_t *si) 2027{ 2028 return _ds_list(si, CATEGORY_PROTOCOL, "getprotoent", NULL, _extract_protocol); 2029} 2030 2031static si_item_t * 2032ds_rpc_byname(si_mod_t *si, const char *name) 2033{ 2034 xpc_object_t payload; 2035 si_item_t *item; 2036 2037 if (!_od_running()) return NULL; 2038 2039 payload = _xpc_query_key_string("name", name); 2040 if (payload == NULL) return NULL; 2041 2042 item = _ds_item(si, CATEGORY_RPC, "getrpcbyname", NULL, _extract_rpc, payload); 2043 2044 xpc_release(payload); 2045 return item; 2046} 2047 2048static si_item_t * 2049ds_rpc_bynumber(si_mod_t *si, int number) 2050{ 2051 xpc_object_t payload; 2052 si_item_t *item; 2053 2054 if (!_od_running()) return NULL; 2055 2056 payload = _xpc_query_key_int("number", number); 2057 if (payload == NULL) return NULL; 2058 2059 item = _ds_item(si, CATEGORY_RPC, "getrpcbynumber", NULL, _extract_rpc, payload); 2060 2061 xpc_release(payload); 2062 return item; 2063} 2064 2065static si_list_t * 2066ds_rpc_all(si_mod_t *si) 2067{ 2068 return _ds_list(si, CATEGORY_RPC, "getrpcent", NULL, _extract_rpc); 2069} 2070 2071static si_item_t * 2072ds_fs_byspec(si_mod_t *si, const char *name) 2073{ 2074 xpc_object_t payload; 2075 si_item_t *item; 2076 2077 if (!_od_running()) return NULL; 2078 2079 payload = _xpc_query_key_string("name", name); 2080 if (payload == NULL) return NULL; 2081 2082 item = _ds_item(si, CATEGORY_FS, "getfsbyname", NULL, _extract_fstab, payload); 2083 2084 xpc_release(payload); 2085 return item; 2086} 2087 2088static si_list_t * 2089ds_fs_all(si_mod_t *si) 2090{ 2091 return _ds_list(si, CATEGORY_FS, "getfsent", NULL, _extract_fstab); 2092} 2093 2094static si_item_t * 2095ds_fs_byfile(si_mod_t *si, const char *name) 2096{ 2097 si_item_t *item; 2098 si_list_t *list; 2099 uint32_t i; 2100 struct fstab *f; 2101 2102 if (!_od_running()) return NULL; 2103 if (name == NULL) return NULL; 2104 2105 list = ds_fs_all(si); 2106 if (list == NULL) return NULL; 2107 2108 item = NULL; 2109 for (i = 0; (i < list->count) && (item == NULL); i++) 2110 { 2111 f = (struct fstab *)((uintptr_t)(list->entry[i]) + sizeof(si_item_t)); 2112 if (string_equal(name, f->fs_file)) item = si_item_retain(list->entry[i]); 2113 } 2114 2115 si_list_release(list); 2116 return item; 2117} 2118 2119static si_item_t * 2120ds_mac_byname(si_mod_t *si, const char *name) 2121{ 2122 xpc_object_t payload; 2123 si_item_t *item; 2124 2125 if (!_od_running()) return NULL; 2126 2127 payload = _xpc_query_key_string("name", name); 2128 if (payload == NULL) return NULL; 2129 2130 item = _ds_item(si, CATEGORY_MAC, "getmacbyname", name, _extract_mac_mac, payload); 2131 2132 xpc_release(payload); 2133 return item; 2134} 2135 2136static si_item_t * 2137ds_mac_bymac(si_mod_t *si, const char *mac) 2138{ 2139 xpc_object_t payload; 2140 si_item_t *item; 2141 char *cmac; 2142 2143 if (!_od_running()) return NULL; 2144 2145 cmac = si_standardize_mac_address(mac); 2146 if (cmac == NULL) return NULL; 2147 2148 payload = xpc_dictionary_create(NULL, NULL, 0); 2149 if (payload == NULL) return NULL; 2150 2151 payload = _xpc_query_key_string("mac", cmac); 2152 item = _ds_item(si, CATEGORY_MAC, "gethostbymac", cmac, _extract_mac_name, payload); 2153 2154 free(cmac); 2155 xpc_release(payload); 2156 2157 return item; 2158} 2159 2160#pragma mark - 2161 2162si_mod_t * 2163si_module_static_ds(void) 2164{ 2165 static const struct si_mod_vtable_s ds_vtable = 2166 { 2167 .sim_is_valid = &_ds_is_valid, 2168 2169 .sim_user_byname = &ds_user_byname, 2170 .sim_user_byuid = &ds_user_byuid, 2171 .sim_user_byuuid = &ds_user_byuuid, 2172 .sim_user_all = &ds_user_all, 2173 2174 .sim_group_byname = &ds_group_byname, 2175 .sim_group_bygid = &ds_group_bygid, 2176 .sim_group_byuuid = &ds_group_byuuid, 2177 .sim_group_all = &ds_group_all, 2178 2179 .sim_grouplist = &ds_grouplist, 2180 2181 .sim_netgroup_byname = &ds_netgroup_byname, 2182 .sim_in_netgroup = &ds_in_netgroup, 2183 2184 .sim_alias_byname = &ds_alias_byname, 2185 .sim_alias_all = &ds_alias_all, 2186 2187 /* host lookups not supported */ 2188 .sim_host_byname = NULL, 2189 .sim_host_byaddr = NULL, 2190 .sim_host_all = NULL, 2191 2192 .sim_network_byname = &ds_network_byname, 2193 .sim_network_byaddr = &ds_network_byaddr, 2194 .sim_network_all = &ds_network_all, 2195 2196 .sim_service_byname = &ds_service_byname, 2197 .sim_service_byport = &ds_service_byport, 2198 .sim_service_all = &ds_service_all, 2199 2200 .sim_protocol_byname = &ds_protocol_byname, 2201 .sim_protocol_bynumber = &ds_protocol_bynumber, 2202 .sim_protocol_all = &ds_protocol_all, 2203 2204 .sim_rpc_byname = &ds_rpc_byname, 2205 .sim_rpc_bynumber = &ds_rpc_bynumber, 2206 .sim_rpc_all = &ds_rpc_all, 2207 2208 .sim_fs_byspec = &ds_fs_byspec, 2209 .sim_fs_byfile = &ds_fs_byfile, 2210 .sim_fs_all = &ds_fs_all, 2211 2212 .sim_mac_byname = &ds_mac_byname, 2213 .sim_mac_bymac = &ds_mac_bymac, 2214 2215 /* si_mac_all not supported */ 2216 .sim_mac_all = NULL, 2217 2218 /* si_addrinfo not supported */ 2219 .sim_wants_addrinfo = NULL, 2220 .sim_addrinfo = NULL, 2221 }; 2222 2223 static si_mod_t si = 2224 { 2225 .vers = 1, 2226 .refcount = 1, 2227 .flags = SI_MOD_FLAG_STATIC, 2228 2229 .private = NULL, 2230 .vtable = &ds_vtable, 2231 }; 2232 2233 static dispatch_once_t once; 2234 dispatch_once(&once, ^{ 2235 pthread_key_create(&_ds_serv_cache_key, _ds_serv_cache_free); 2236 2237 si.name = strdup("ds"); 2238 ds_si_private_t *pp = calloc(1, sizeof(ds_si_private_t)); 2239 2240 if (pp != NULL) 2241 { 2242 pp->notify_token_global = -1; 2243 pp->notify_token_user = -1; 2244 pp->notify_token_group = -1; 2245 pp->notify_token_service = -1; 2246 } 2247 2248 /* 2249 * Don't register for notifications if the cache is disabled. 2250 * notifyd (notably) disables the cache to prevent deadlocks. 2251 */ 2252 if (gL1CacheEnabled != 0) 2253 { 2254 /* 2255 * Errors in registering for cache invalidation notifications are ignored. 2256 * If there are failures, the tokens remain set to -1 which just causes 2257 * cached items to be invalidated. 2258 */ 2259 notify_register_check(kNotifyDSCacheInvalidation, &(pp->notify_token_global)); 2260 notify_register_check(kNotifyDSCacheInvalidationUser, &(pp->notify_token_user)); 2261 notify_register_check(kNotifyDSCacheInvalidationGroup, &(pp->notify_token_group)); 2262 notify_register_check(kNotifyDSCacheInvalidationService, &(pp->notify_token_service)); 2263 } 2264 2265 si.private = pp; 2266 }); 2267 2268 return &si; 2269} 2270 2271#endif /* DS_AVAILABLE */ 2272