1/* 2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file 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 file 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 * file. 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#include <sys/types.h> 25#include <sys/socket.h> 26#include <net/ethernet.h> 27#include <libkern/OSAtomic.h> 28#include <dlfcn.h> 29#include <string.h> 30#include <stdio.h> 31#include <errno.h> 32#include <pthread.h> 33#include <mach/mach.h> 34#include <dispatch/dispatch.h> 35#include <dispatch/private.h> 36#include "si_module.h" 37 38#define PLUGIN_DIR_PATH "/usr/lib/info" 39#define PLUGIN_BUNDLE_SUFFIX "so" 40 41#define WORKUNIT_CANCELLED 0x00000001 42#define WORKUNIT_RETURNS_LIST 0x00000002 43 44#ifdef __BIG_ENDIAN__ 45#define WORKUNIT_CANCELLED_BIT_ADDRESS 31 46#else 47#define WORKUNIT_CANCELLED_BIT_ADDRESS 7 48#endif 49 50typedef struct si_async_workunit_s 51{ 52 si_mod_t *si; 53 uint32_t call; 54 char *str1; 55 char *str2; 56 char *str3; 57 uint32_t num1; 58 uint32_t num2; 59 uint32_t num3; 60 uint32_t num4; 61 uint32_t err; 62 /* async support below */ 63 uint32_t flags; 64 int32_t refcount; 65 void *callback; 66 void *context; 67 mach_port_t port; 68 mach_port_t send; 69 si_item_t *resitem; 70 si_list_t *reslist; 71 struct si_async_workunit_s *next; 72} si_async_workunit_t; 73 74static si_mod_t **module_list = NULL; 75static uint32_t module_count = 0; 76static pthread_mutex_t module_mutex = PTHREAD_MUTEX_INITIALIZER; 77static si_async_workunit_t *si_async_worklist = NULL; 78 79si_mod_t *si_module_static_search(void); 80si_mod_t *si_module_static_cache(void); 81si_mod_t *si_module_static_file(void); 82#ifdef DS_AVAILABLE 83si_mod_t *si_module_static_ds(void); 84#endif 85si_mod_t *si_module_static_mdns(void); 86 87static void * 88si_mod_dlsym(void *so, const char *name, const char *sym) 89{ 90 char *str; 91 void *out; 92 93 if ((so == NULL) || (name == NULL) || (sym == NULL)) return NULL; 94 95 str = NULL; 96 asprintf(&str, "%s_%s", name, sym); 97 if (str == NULL) return NULL; 98 99 out = dlsym(so, str); 100 free(str); 101 return out; 102} 103 104si_mod_t * 105si_module_with_path(const char *path, const char *name) 106{ 107 void *so; 108 int (*si_sym_init)(si_mod_t *); 109 void (*si_sym_close)(si_mod_t *); 110 int status; 111 si_mod_t *out; 112 char *outname; 113 114 if ((path == NULL) || (name == NULL)) 115 { 116 errno = EINVAL; 117 return NULL; 118 } 119 120 so = dlopen(path, RTLD_LOCAL); 121 if (so == NULL) return NULL; 122 123 si_sym_init = si_mod_dlsym(so, name, "init"); 124 if (si_sym_init == NULL) 125 { 126 dlclose(so); 127 errno = ECONNREFUSED; 128 return NULL; 129 } 130 131 si_sym_close = si_mod_dlsym(so, name, "close"); 132 if (si_sym_close == NULL) 133 { 134 dlclose(so); 135 errno = ECONNREFUSED; 136 return NULL; 137 } 138 139 out = (si_mod_t *)calloc(1, sizeof(si_mod_t)); 140 outname = strdup(name); 141 142 if ((out == NULL) || (outname == NULL)) 143 { 144 free(out); 145 free(outname); 146 dlclose(so); 147 errno = ENOMEM; 148 return NULL; 149 } 150 151 out->name = outname; 152 out->refcount = 1; 153 out->flags = 0; 154 out->bundle = so; 155 156 status = si_sym_init(out); 157 if (status != 0) 158 { 159 dlclose(so); 160 free(out); 161 free(outname); 162 errno = ECONNREFUSED; 163 return NULL; 164 } 165 166 return out; 167} 168 169si_mod_t * 170si_module_with_name(const char *name) 171{ 172 static struct 173 { 174 const char *name; 175 si_mod_t *(*init)(void); 176 si_mod_t *module; 177 } modules[] = 178 { 179 { "search", si_module_static_search, NULL }, 180 { "cache", si_module_static_cache, NULL }, 181 { "file", si_module_static_file, NULL }, 182#ifdef DS_AVAILABLE 183 { "ds", si_module_static_ds, NULL }, 184#endif 185 { "mdns", si_module_static_mdns, NULL }, 186 { NULL, NULL }, 187 }; 188 189 si_mod_t *si = NULL; 190 int i; 191 192 /* 193 * We don't need to worry about locking during initialization 194 * because all modules init routine returns static storage. 195 */ 196 197 /* Find the module by name */ 198 for (i = 0; modules[i].name != NULL; ++i) 199 { 200 if (string_equal(name, modules[i].name)) 201 { 202 si = modules[i].module; 203 if (si == NULL) 204 { 205 si = modules[i].init(); 206 modules[i].module = si; 207 } 208 209 break; 210 } 211 } 212 213 if (si != NULL) return si; 214 215 pthread_mutex_lock(&module_mutex); 216 char *path = NULL; 217 218 asprintf(&path, "%s/%s.%s", PLUGIN_DIR_PATH, name, PLUGIN_BUNDLE_SUFFIX); 219 220 if (path == NULL) 221 { 222 errno = ENOMEM; 223 pthread_mutex_unlock(&module_mutex); 224 return NULL; 225 } 226 227 si = si_module_with_path(path, name); 228 free(path); 229 230 if (si == NULL) 231 { 232 pthread_mutex_unlock(&module_mutex); 233 return NULL; 234 } 235 236 /* add out to module_list */ 237 module_list = (si_mod_t **)reallocf(module_list, (module_count + 1) * sizeof(si_mod_t *)); 238 if (module_list == NULL) 239 { 240 pthread_mutex_unlock(&module_mutex); 241 return si; 242 } 243 244 module_list[module_count] = si; 245 module_count++; 246 247 pthread_mutex_unlock(&module_mutex); 248 249 return si; 250} 251 252si_mod_t * 253si_module_retain(si_mod_t *si) 254{ 255 if (si == NULL) return NULL; 256 if (si->flags & SI_MOD_FLAG_STATIC) return si; 257 258 OSAtomicIncrement32Barrier(&si->refcount); 259 260 return si; 261} 262 263void 264si_module_release(si_mod_t *si) 265{ 266 int32_t i; 267 268 if (si == NULL) return; 269 if (si->flags & SI_MOD_FLAG_STATIC) return; 270 271 i = OSAtomicDecrement32Barrier(&si->refcount); 272 if (i > 0) return; 273 274 pthread_mutex_lock(&module_mutex); 275 276 for (i = 0; (i < module_count) && (module_list[i] != si); i++); 277 if (i >= module_count) 278 { 279 pthread_mutex_unlock(&module_mutex); 280 return; 281 } 282 283 if (module_count == 1) 284 { 285 free(module_list); 286 module_list = NULL; 287 module_count = 0; 288 pthread_mutex_unlock(&module_mutex); 289 return; 290 } 291 292 for (i++; i < module_count; i++) module_list[i - 1] = module_list[i]; 293 module_count--; 294 module_list = (si_mod_t **)reallocf(module_list, module_count * sizeof(si_mod_t *)); 295 if (module_list == NULL) module_count = 0; 296 297 pthread_mutex_unlock(&module_mutex); 298 299 if (si->vtable->sim_close != NULL) si->vtable->sim_close(si); 300 if (si->bundle != NULL) dlclose(si->bundle); 301 free(si->name); 302 free(si); 303} 304 305const char * 306si_module_name(si_mod_t *si) 307{ 308 if (si == NULL) return NULL; 309 310 return (const char *)si->name; 311} 312 313int 314si_module_vers(si_mod_t *si) 315{ 316 if (si == NULL) return 0; 317 318 return si->vers; 319} 320 321int 322si_item_match(si_item_t *item, int cat, const void *name, uint32_t num, int which) 323{ 324 int i; 325 union 326 { 327 char *x; 328 struct passwd *u; 329 struct group *g; 330 struct grouplist_s *l; 331 struct aliasent *a; 332 struct hostent *h; 333 struct netent *n; 334 struct servent *s; 335 struct protoent *p; 336 struct rpcent *r; 337 struct fstab *f; 338 struct mac_s *m; 339 } ent; 340 341 if (item == NULL) return 0; 342 if (which == SEL_ALL) return 1; 343 if ((which == SEL_NAME) && (name == NULL)) return 0; 344 345 ent.x = (char *)((uintptr_t)item + sizeof(si_item_t)); 346 347 switch (cat) 348 { 349 case CATEGORY_USER: 350 { 351 if ((which == SEL_NAME) && (string_equal(name, ent.u->pw_name))) return 1; 352 else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.u->pw_uid)) return 1; 353 return 0; 354 } 355 case CATEGORY_GROUP: 356 { 357 if ((which == SEL_NAME) && (string_equal(name, ent.g->gr_name))) return 1; 358 else if ((which == SEL_NUMBER) && (num == (uint32_t)ent.g->gr_gid)) return 1; 359 return 0; 360 } 361 case CATEGORY_GROUPLIST: 362 { 363 if ((which == SEL_NAME) && (string_equal(name, ent.l->gl_user))) return 1; 364 return 0; 365 } 366 case CATEGORY_ALIAS: 367 { 368 if ((which == SEL_NAME) && (string_equal(name, ent.a->alias_name))) return 1; 369 return 0; 370 } 371 case CATEGORY_HOST_IPV4: 372 case CATEGORY_HOST_IPV6: 373 { 374 /* N.B. address family is passed in num variable */ 375 if (ent.h->h_addrtype != num) return 0; 376 if (which == SEL_NAME) 377 { 378 if (string_equal(name, ent.h->h_name)) return 1; 379 if (ent.h->h_aliases != NULL) 380 { 381 for (i = 0; ent.h->h_aliases[i] != NULL; i++) 382 { 383 if (string_equal(name, ent.h->h_aliases[i])) return 1; 384 } 385 } 386 } 387 else if (which == SEL_NUMBER) 388 { 389 if (memcmp(name, ent.h->h_addr_list[0], ent.h->h_length) == 0) return 1; 390 } 391 return 0; 392 } 393 case CATEGORY_NETWORK: 394 { 395 if (which == SEL_NAME) 396 { 397 if (string_equal(name, ent.n->n_name)) return 1; 398 if (ent.n->n_aliases != NULL) 399 { 400 for (i = 0; ent.n->n_aliases[i] != NULL; i++) 401 { 402 if (string_equal(name, ent.n->n_aliases[i])) return 1; 403 } 404 } 405 } 406 else if (which == SEL_NUMBER) 407 { 408 if (num == ent.n->n_net) return 1; 409 } 410 return 0; 411 } 412 case CATEGORY_SERVICE: 413 { 414 if (which == SEL_NAME) 415 { 416 /* N.B. for SEL_NAME, num is 0 (don't care), 1 (udp) or 2 (tcp) */ 417 if ((num == 1) && (string_not_equal("udp", ent.s->s_proto))) return 0; 418 if ((num == 2) && (string_not_equal("tcp", ent.s->s_proto))) return 0; 419 420 if (string_equal(name, ent.s->s_name)) return 1; 421 if (ent.s->s_aliases != NULL) 422 { 423 for (i = 0; ent.s->s_aliases[i] != NULL; i++) 424 { 425 if (string_equal(name, ent.s->s_aliases[i])) return 1; 426 } 427 } 428 } 429 else if (which == SEL_NUMBER) 430 { 431 /* N.B. for SEL_NUMBER, protocol is sent in name variable */ 432 if ((name != NULL) && (string_not_equal(name, ent.s->s_proto))) return 0; 433 if (num == ent.s->s_port) return 1; 434 } 435 return 0; 436 } 437 case CATEGORY_PROTOCOL: 438 { 439 if (which == SEL_NAME) 440 { 441 if (string_equal(name, ent.p->p_name)) return 1; 442 if (ent.p->p_aliases != NULL) 443 { 444 for (i = 0; ent.p->p_aliases[i] != NULL; i++) 445 { 446 if (string_equal(name, ent.p->p_aliases[i])) return 1; 447 } 448 } 449 } 450 else if (which == SEL_NUMBER) 451 { 452 if (num == ent.p->p_proto) return 1; 453 } 454 return 0; 455 } 456 case CATEGORY_RPC: 457 { 458 if (which == SEL_NAME) 459 { 460 if (string_equal(name, ent.r->r_name)) return 1; 461 if (ent.r->r_aliases != NULL) 462 { 463 for (i = 0; ent.r->r_aliases[i] != NULL; i++) 464 { 465 if (string_equal(name, ent.r->r_aliases[i])) return 1; 466 } 467 } 468 } 469 else if (which == SEL_NUMBER) 470 { 471 if (num == ent.r->r_number) return 1; 472 } 473 return 0; 474 } 475 case CATEGORY_FS: 476 { 477 if ((which == SEL_NAME) && (string_equal(name, ent.f->fs_spec))) return 1; 478 if ((which == SEL_NUMBER) && (string_equal(name, ent.f->fs_file))) return 1; 479 return 0; 480 } 481 case CATEGORY_MAC: 482 { 483 if ((which == SEL_NAME) && (string_equal(name, ent.m->host))) return 1; 484 if ((which == SEL_NUMBER) && (string_equal(name, ent.m->mac))) return 1; 485 return 0; 486 } 487 default: return 0; 488 } 489 490 return 0; 491} 492 493int 494si_item_is_valid(si_item_t *item) 495{ 496 si_mod_t *si; 497 498 if (item == NULL) return 0; 499 500 si = item->src; 501 502 if (si == NULL) return 0; 503 if (si->vtable->sim_is_valid == NULL) return 0; 504 505 return si->vtable->sim_is_valid(si, item); 506} 507 508si_item_t * 509si_user_byname(si_mod_t *si, const char *name) 510{ 511 if (si == NULL) return NULL; 512 if (si->vtable->sim_user_byname == NULL) return NULL; 513 return si->vtable->sim_user_byname(si, name); 514} 515 516si_item_t * 517si_user_byuid(si_mod_t *si, uid_t uid) 518{ 519 if (si == NULL) return NULL; 520 if (si->vtable->sim_user_byuid == NULL) return NULL; 521 return si->vtable->sim_user_byuid(si, uid); 522} 523 524si_item_t * 525si_user_byuuid(si_mod_t *si, uuid_t uuid) 526{ 527 if (si == NULL) return NULL; 528 if (si->vtable->sim_user_byuuid == NULL) return NULL; 529 return si->vtable->sim_user_byuuid(si, uuid); 530} 531 532si_list_t * 533si_user_all(si_mod_t *si) 534{ 535 if (si == NULL) return NULL; 536 if (si->vtable->sim_user_all == NULL) return NULL; 537 return si->vtable->sim_user_all(si); 538} 539 540si_item_t * 541si_group_byname(si_mod_t *si, const char *name) 542{ 543 if (si == NULL) return NULL; 544 if (si->vtable->sim_group_byname == NULL) return NULL; 545 return si->vtable->sim_group_byname(si, name); 546} 547 548si_item_t * 549si_group_bygid(si_mod_t *si, gid_t gid) 550{ 551 if (si == NULL) return NULL; 552 if (si->vtable->sim_group_bygid == NULL) return NULL; 553 return si->vtable->sim_group_bygid(si, gid); 554} 555 556si_item_t * 557si_group_byuuid(si_mod_t *si, uuid_t uuid) 558{ 559 if (si == NULL) return NULL; 560 if (si->vtable->sim_group_byuuid == NULL) return NULL; 561 return si->vtable->sim_group_byuuid(si, uuid); 562} 563 564si_list_t * 565si_group_all(si_mod_t *si) 566{ 567 if (si == NULL) return NULL; 568 if (si->vtable->sim_group_all == NULL) return NULL; 569 return si->vtable->sim_group_all(si); 570} 571 572si_item_t * 573si_grouplist(si_mod_t *si, const char *name, uint32_t count) 574{ 575 if (si == NULL) return NULL; 576 if (si->vtable->sim_grouplist == NULL) return NULL; 577 return si->vtable->sim_grouplist(si, name, count); 578} 579 580si_list_t * 581si_netgroup_byname(struct si_mod_s *si, const char *name) 582{ 583 if (si == NULL) return NULL; 584 if (si->vtable->sim_netgroup_byname == NULL) return NULL; 585 return si->vtable->sim_netgroup_byname(si, name); 586} 587 588int 589si_in_netgroup(struct si_mod_s *si, const char *name, const char *host, const char *user, const char *domain) 590{ 591 if (si == NULL) return 0; 592 if (si->vtable->sim_in_netgroup == NULL) return 0; 593 return si->vtable->sim_in_netgroup(si, name, host, user, domain); 594} 595 596si_item_t * 597si_alias_byname(si_mod_t *si, const char *name) 598{ 599 if (si == NULL) return NULL; 600 if (si->vtable->sim_alias_byname == NULL) return NULL; 601 return si->vtable->sim_alias_byname(si, name); 602} 603 604si_list_t * 605si_alias_all(si_mod_t *si) 606{ 607 if (si == NULL) return NULL; 608 if (si->vtable->sim_alias_all == NULL) return NULL; 609 return si->vtable->sim_alias_all(si); 610} 611 612si_item_t * 613si_host_byname(si_mod_t *si, const char *name, int af, const char *interface, uint32_t *err) 614{ 615 if (si == NULL) return NULL; 616 if (si->vtable->sim_host_byname == NULL) return NULL; 617 return si->vtable->sim_host_byname(si, name, af, interface, err); 618} 619 620si_item_t * 621si_host_byaddr(si_mod_t *si, const void *addr, int af, const char *interface, uint32_t *err) 622{ 623 if (si == NULL) return NULL; 624 if (si->vtable->sim_host_byaddr == NULL) return NULL; 625 return si->vtable->sim_host_byaddr(si, addr, af, interface, err); 626} 627 628si_list_t * 629si_host_all(si_mod_t *si) 630{ 631 if (si == NULL) return NULL; 632 if (si->vtable->sim_host_all == NULL) return NULL; 633 return si->vtable->sim_host_all(si); 634} 635 636si_item_t * 637si_mac_byname(struct si_mod_s *si, const char *name) 638{ 639 if (si == NULL) return NULL; 640 if (si->vtable->sim_mac_byname == NULL) return NULL; 641 return si->vtable->sim_mac_byname(si, name); 642} 643 644si_item_t * 645si_mac_bymac(struct si_mod_s *si, const char *mac) 646{ 647 if (si == NULL) return NULL; 648 if (si->vtable->sim_mac_bymac == NULL) return NULL; 649 return si->vtable->sim_mac_bymac(si, mac); 650} 651 652si_list_t * 653si_mac_all(si_mod_t *si) 654{ 655 if (si == NULL) return NULL; 656 if (si->vtable->sim_mac_all == NULL) return NULL; 657 return si->vtable->sim_mac_all(si); 658} 659 660si_item_t * 661si_network_byname(si_mod_t *si, const char *name) 662{ 663 if (si == NULL) return NULL; 664 if (si->vtable->sim_network_byname == NULL) return NULL; 665 return si->vtable->sim_network_byname(si, name); 666} 667 668si_item_t * 669si_network_byaddr(si_mod_t *si, uint32_t addr) 670{ 671 if (si == NULL) return NULL; 672 if (si->vtable->sim_network_byaddr == NULL) return NULL; 673 return si->vtable->sim_network_byaddr(si, addr); 674} 675 676si_list_t * 677si_network_all(si_mod_t *si) 678{ 679 if (si == NULL) return NULL; 680 if (si->vtable->sim_network_all == NULL) return NULL; 681 return si->vtable->sim_network_all(si); 682} 683 684si_item_t * 685si_service_byname(si_mod_t *si, const char *name, const char *proto) 686{ 687 if (si == NULL) return NULL; 688 if (si->vtable->sim_service_byname == NULL) return NULL; 689 return si->vtable->sim_service_byname(si, name, proto); 690} 691 692si_item_t * 693si_service_byport(si_mod_t *si, int port, const char *proto) 694{ 695 if (si == NULL) return NULL; 696 if (si->vtable->sim_service_byport == NULL) return NULL; 697 return si->vtable->sim_service_byport(si, port, proto); 698} 699 700si_list_t * 701si_service_all(si_mod_t *si) 702{ 703 if (si == NULL) return NULL; 704 if (si->vtable->sim_service_all == NULL) return NULL; 705 return si->vtable->sim_service_all(si); 706} 707 708si_item_t * 709si_protocol_byname(si_mod_t *si, const char *name) 710{ 711 if (si == NULL) return NULL; 712 if (si->vtable->sim_protocol_byname == NULL) return NULL; 713 return si->vtable->sim_protocol_byname(si, name); 714} 715 716si_item_t * 717si_protocol_bynumber(si_mod_t *si, uint32_t number) 718{ 719 if (si == NULL) return NULL; 720 if (si->vtable->sim_protocol_bynumber == NULL) return NULL; 721 return si->vtable->sim_protocol_bynumber(si, number); 722} 723 724si_list_t * 725si_protocol_all(si_mod_t *si) 726{ 727 if (si == NULL) return NULL; 728 if (si->vtable->sim_protocol_all == NULL) return NULL; 729 return si->vtable->sim_protocol_all(si); 730} 731 732si_item_t * 733si_rpc_byname(si_mod_t *si, const char *name) 734{ 735 if (si == NULL) return NULL; 736 if (si->vtable->sim_rpc_byname == NULL) return NULL; 737 return si->vtable->sim_rpc_byname(si, name); 738} 739 740si_item_t * 741si_rpc_bynumber(si_mod_t *si, int number) 742{ 743 if (si == NULL) return NULL; 744 if (si->vtable->sim_rpc_bynumber == NULL) return NULL; 745 return si->vtable->sim_rpc_bynumber(si, number); 746} 747 748si_list_t * 749si_rpc_all(si_mod_t *si) 750{ 751 if (si == NULL) return NULL; 752 if (si->vtable->sim_rpc_all == NULL) return NULL; 753 return si->vtable->sim_rpc_all(si); 754} 755 756si_item_t * 757si_fs_byspec(si_mod_t *si, const char *spec) 758{ 759 if (si == NULL) return NULL; 760 if (si->vtable->sim_fs_byspec == NULL) return NULL; 761 return si->vtable->sim_fs_byspec(si, spec); 762} 763 764si_item_t * 765si_fs_byfile(si_mod_t *si, const char *file) 766{ 767 if (si == NULL) return NULL; 768 if (si->vtable->sim_fs_byfile == NULL) return NULL; 769 return si->vtable->sim_fs_byfile(si, file); 770} 771 772si_list_t * 773si_fs_all(si_mod_t *si) 774{ 775 if (si == NULL) return NULL; 776 if (si->vtable->sim_fs_all == NULL) return NULL; 777 return si->vtable->sim_fs_all(si); 778} 779 780si_item_t * 781si_item_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t *err) 782{ 783 if (si == NULL) return NULL; 784 785 switch (call) 786 { 787 case SI_CALL_USER_BYNAME: return si_user_byname(si, str1); 788 case SI_CALL_USER_BYUID: return si_user_byuid(si, (uid_t)num1); 789 case SI_CALL_GROUP_BYNAME: return si_group_byname(si, str1); 790 case SI_CALL_GROUP_BYGID: return si_group_bygid(si, (gid_t)num1); 791 case SI_CALL_GROUPLIST: return si_grouplist(si, str1, (int) num1); 792 case SI_CALL_ALIAS_BYNAME: return si_alias_byname(si, str1); 793 case SI_CALL_HOST_BYNAME: return si_host_byname(si, str1, num1, str3, err); 794 case SI_CALL_HOST_BYADDR: return si_host_byaddr(si, (void *)str1, num1, str3, err); 795 case SI_CALL_NETWORK_BYNAME: return si_network_byname(si, str1); 796 case SI_CALL_NETWORK_BYADDR: return si_network_byaddr(si, num1); 797 case SI_CALL_SERVICE_BYNAME: return si_service_byname(si, str1, str2); 798 case SI_CALL_SERVICE_BYPORT: return si_service_byport(si, num1, str2); 799 case SI_CALL_PROTOCOL_BYNAME: return si_protocol_byname(si, str1); 800 case SI_CALL_PROTOCOL_BYNUMBER: return si_protocol_bynumber(si, num1); 801 case SI_CALL_RPC_BYNAME: return si_network_byname(si, str1); 802 case SI_CALL_RPC_BYNUMBER: return si_rpc_bynumber(si, num1); 803 case SI_CALL_FS_BYSPEC: return si_fs_byspec(si, str1); 804 case SI_CALL_FS_BYFILE: return si_fs_byfile(si, str1); 805 case SI_CALL_NAMEINFO: return si_nameinfo(si, (const struct sockaddr *)str1, num1, str3, err); 806 case SI_CALL_IPNODE_BYNAME: return si_ipnode_byname(si, (const char *)str1, num1, num2, str3, err); 807 case SI_CALL_MAC_BYNAME: return si_mac_byname(si, (const char *)str1); 808 case SI_CALL_MAC_BYMAC: return si_mac_bymac(si, (const char *)str1); 809 810 /* Support for DNS async calls */ 811 case SI_CALL_DNS_QUERY: 812 case SI_CALL_DNS_SEARCH: 813 { 814 if (si->vtable->sim_item_call == NULL) return NULL; 815 return si->vtable->sim_item_call(si, call, str1, str2, str3, num1, num2, err); 816 } 817 818 default: return NULL; 819 } 820 821 return NULL; 822} 823 824si_list_t * 825si_list_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, uint32_t *err) 826{ 827 if (si == NULL) return NULL; 828 829 switch (call) 830 { 831 case SI_CALL_USER_ALL: return si_user_all(si); 832 case SI_CALL_GROUP_ALL: return si_group_all(si); 833 case SI_CALL_ALIAS_ALL: return si_alias_all(si); 834 case SI_CALL_HOST_ALL: return si_host_all(si); 835 case SI_CALL_NETWORK_ALL: return si_network_all(si); 836 case SI_CALL_SERVICE_ALL: return si_service_all(si); 837 case SI_CALL_PROTOCOL_ALL: return si_protocol_all(si); 838 case SI_CALL_RPC_ALL: return si_rpc_all(si); 839 case SI_CALL_FS_ALL: return si_fs_all(si); 840 case SI_CALL_MAC_ALL: return si_mac_all(si); 841 case SI_CALL_ADDRINFO: return si_addrinfo(si, str1, str2, num1, num2, num3, num4, str3, err); 842 default: return NULL; 843 } 844 845 return NULL; 846} 847 848static void 849si_async_worklist_add_unit(si_async_workunit_t *r) 850{ 851 pthread_mutex_lock(&module_mutex); 852 r->next = si_async_worklist; 853 si_async_worklist = r; 854 pthread_mutex_unlock(&module_mutex); 855} 856 857static void 858si_async_worklist_remove_unit(si_async_workunit_t *r) 859{ 860 si_async_workunit_t *x; 861 862 pthread_mutex_lock(&module_mutex); 863 if (si_async_worklist == r) 864 { 865 si_async_worklist = r->next; 866 } 867 else 868 { 869 for (x = si_async_worklist; (x != NULL) && (x->next != r); x = x->next) {;} 870 if (x != NULL) x->next = r->next; 871 } 872 pthread_mutex_unlock(&module_mutex); 873} 874 875static si_async_workunit_t* 876si_async_worklist_find_unit(mach_port_t p) 877{ 878 si_async_workunit_t *r; 879 880 pthread_mutex_lock(&module_mutex); 881 for (r = si_async_worklist; (r != NULL) && (r->port != p); r = r->next) {;} 882 pthread_mutex_unlock(&module_mutex); 883 884 return r; 885} 886 887static si_async_workunit_t * 888si_async_workunit_create(si_mod_t *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context) 889{ 890 si_async_workunit_t *r; 891 kern_return_t status; 892 mach_port_t reply, send; 893 mach_msg_type_name_t type; 894 char *s1, *s2, *s3; 895 896 s1 = NULL; 897 s2 = NULL; 898 s3 = NULL; 899 900 if (si_call_str1_is_buffer(call)) 901 { 902 if (num3 > 0) 903 { 904 s1 = calloc(1, num3); 905 if (s1 == NULL) return NULL; 906 memcpy(s1, str1, num3); 907 } 908 } 909 else if (str1 != NULL) 910 { 911 s1 = strdup(str1); 912 if (s1 == NULL) return NULL; 913 } 914 915 if (str2 != NULL) 916 { 917 s2 = strdup(str2); 918 if (s2 == NULL) 919 { 920 if (s1 != NULL) free(s1); 921 return NULL; 922 } 923 } 924 925 if (str3 != NULL) 926 { 927 s3 = strdup(str3); 928 if (s3 == NULL) 929 { 930 if (s1 != NULL) free(s1); 931 if (s2 != NULL) free(s2); 932 return NULL; 933 } 934 } 935 936 r = (si_async_workunit_t *)calloc(1, sizeof(si_async_workunit_t)); 937 if (r == NULL) 938 { 939 if (s1 != NULL) free(s1); 940 if (s2 != NULL) free(s2); 941 if (s3 != NULL) free(s3); 942 return NULL; 943 } 944 945 reply = MACH_PORT_NULL; 946 send = MACH_PORT_NULL; 947 type = 0; 948 949 status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &reply); 950 if (status == KERN_SUCCESS) status = mach_port_extract_right(mach_task_self(), reply, MACH_MSG_TYPE_MAKE_SEND_ONCE, &send, &type); 951 if (status != KERN_SUCCESS) 952 { 953 if (reply != MACH_PORT_NULL) mach_port_mod_refs(mach_task_self(), reply, MACH_PORT_RIGHT_RECEIVE, -1); 954 if (s1 != NULL) free(s1); 955 if (s2 != NULL) free(s2); 956 if (s3 != NULL) free(s3); 957 free(r); 958 return NULL; 959 } 960 961 r->si = si; 962 r->call = call; 963 r->str1 = s1; 964 r->str2 = s2; 965 r->str3 = s3; 966 r->num1 = num1; 967 r->num2 = num2; 968 r->num3 = num3; 969 r->num4 = num4; 970 971 r->refcount = 2; 972 r->flags = 0; 973 if (si_call_returns_list(call)) r->flags |= WORKUNIT_RETURNS_LIST; 974 975 r->callback = callback; 976 r->context = context; 977 r->port = reply; 978 r->send = send; 979 980 si_async_worklist_add_unit(r); 981 982 return r; 983} 984 985static void 986si_async_workunit_release(si_async_workunit_t *r) 987{ 988 if (r == NULL) return; 989 990 if (OSAtomicDecrement32Barrier(&(r->refcount)) != 0) return; 991 992#ifdef CALL_TRACE 993 fprintf(stderr, "** %s freeing worklist item %p\n", __func__, r); 994#endif 995 996 si_async_worklist_remove_unit(r); 997 998 if (r->resitem != NULL) si_item_release(r->resitem); 999 if (r->reslist != NULL) si_list_release(r->reslist); 1000 1001 if (r->str1 != NULL) free(r->str1); 1002 if (r->str2 != NULL) free(r->str2); 1003 if (r->str3 != NULL) free(r->str3); 1004 1005 /* release send-once right if it has not been used */ 1006 if (r->send != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), r->send); 1007 1008 /* release receive right */ 1009 mach_port_mod_refs(mach_task_self(), r->port, MACH_PORT_RIGHT_RECEIVE, -1); 1010 1011 free(r); 1012} 1013 1014static void 1015si_async_launchpad(si_async_workunit_t *r) 1016{ 1017 kern_return_t status; 1018 mach_msg_empty_send_t msg; 1019 1020#ifdef CALL_TRACE 1021 fprintf(stderr, "** %s starting worklist item %p\n", __func__, r); 1022#endif 1023 1024 if (r->flags & WORKUNIT_CANCELLED) 1025 { 1026 si_async_workunit_release(r); 1027#ifdef CALL_TRACE 1028 fprintf(stderr, "** %s worklist item %p was cancelled early\n", __func__, r); 1029#endif 1030 return; 1031 } 1032 1033 if (r->flags & WORKUNIT_RETURNS_LIST) r->reslist = si_list_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, r->num3, r->num4, &(r->err)); 1034 else r->resitem = si_item_call(r->si, r->call, r->str1, r->str2, r->str3, r->num1, r->num2, &(r->err)); 1035 1036 /* 1037 * Test and set the cancelled flag. 1038 * If it was set, then this work item was cancelled. 1039 * Otherwise, setting it here prevents si_async_cancel from cancelling: 1040 * too late to cancel now! 1041 */ 1042 if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1) 1043 { 1044 si_async_workunit_release(r); 1045#ifdef CALL_TRACE 1046 fprintf(stderr, "** %s worklist item %p was cancelled in flight\n", __func__, r); 1047#endif 1048 return; 1049 } 1050#ifdef CALL_TRACE 1051 else fprintf(stderr, "** %s worklist item %p flags are now 0x%08x\n", __func__, r, r->flags); 1052#endif 1053 1054 memset(&msg, 0, sizeof(mach_msg_empty_send_t)); 1055 1056 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, MACH_MSGH_BITS_ZERO); 1057 msg.header.msgh_remote_port = r->send; 1058 r->send = MACH_PORT_NULL; 1059 msg.header.msgh_local_port = MACH_PORT_NULL; 1060 msg.header.msgh_size = sizeof(mach_msg_empty_send_t); 1061 msg.header.msgh_id = r->call; 1062 1063 status = mach_msg(&(msg.header), MACH_SEND_MSG, msg.header.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 1064 if (status != MACH_MSG_SUCCESS) 1065 { 1066 /* receiver failed - clean up to avoid a port leak */ 1067 mach_msg_destroy(&(msg.header)); 1068#ifdef CALL_TRACE 1069 fprintf(stderr, "** %s mach message send failed for worklist item %p\n", __func__, r); 1070#endif 1071 } 1072 1073 si_async_workunit_release(r); 1074 1075 /* 1076 * The client is now responsible for calling si_async_handle_reply, 1077 * which will invoke the client's callback and then release the workunit. 1078 */ 1079 1080#ifdef CALL_TRACE 1081 fprintf(stderr, "** %s completed async worklist item %p\n", __func__, r); 1082#endif 1083} 1084 1085mach_port_t 1086si_async_call(struct si_mod_s *si, int call, const char *str1, const char *str2, const char *str3, uint32_t num1, uint32_t num2, uint32_t num3, uint32_t num4, void *callback, void *context) 1087{ 1088 si_async_workunit_t *req; 1089 1090 if (si == NULL) return MACH_PORT_NULL; 1091 if (callback == NULL) return MACH_PORT_NULL; 1092 1093 /* if module does async on it's own, hand off the call */ 1094 if (si->vtable->sim_async_call != NULL) 1095 { 1096 return si->vtable->sim_async_call(si, call, str1, str2, str3, num1, num2, num3, num4, callback, context); 1097 } 1098 1099 req = si_async_workunit_create(si, call, str1, str2, str3, num1, num2, num3, num4, callback, context); 1100 if (req == NULL) return MACH_PORT_NULL; 1101 1102 /* queue the work on the global low-priority dispatch queue */ 1103#ifdef CALL_TRACE 1104 fprintf(stderr, "** %s dispatching worklist item %p\n", __func__, req); 1105#endif 1106 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_OVERCOMMIT), ^{ si_async_launchpad(req); }); 1107 1108 return req->port; 1109} 1110 1111void 1112si_async_cancel(mach_port_t p) 1113{ 1114 si_async_workunit_t *r; 1115 1116 r = si_async_worklist_find_unit(p); 1117 if (r == NULL) 1118 { 1119#ifdef CALL_TRACE 1120 fprintf(stderr, "** %s can't find worklist item\n", __func__); 1121#endif 1122 return; 1123 } 1124 1125 /* 1126 * Test and set the WORKUNIT_CANCELLED flag. 1127 * If it was already set, this work item has been executed - too late to really cancel. 1128 */ 1129 if (OSAtomicTestAndSetBarrier(WORKUNIT_CANCELLED_BIT_ADDRESS, &(r->flags)) == 1) 1130 { 1131 /* already executed */ 1132#ifdef CALL_TRACE 1133 fprintf(stderr, "** %s worklist item %p has executed\n", __func__, r); 1134#endif 1135 } 1136 1137#ifdef CALL_TRACE 1138 fprintf(stderr, "** %s calling worklist item %p callback SI_STATUS_CALL_CANCELLED\n", __func__, r); 1139#endif 1140 1141 if (r->callback != NULL) 1142 { 1143 if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context); 1144 else ((item_async_callback)(r->callback))(NULL, SI_STATUS_CALL_CANCELLED, r->context); 1145 } 1146 1147 si_async_workunit_release(r); 1148} 1149 1150void 1151si_async_handle_reply(mach_msg_header_t *msg) 1152{ 1153 si_async_workunit_t *r; 1154 mach_port_t reply = msg->msgh_local_port; 1155 1156 r = si_async_worklist_find_unit(reply); 1157 if (r == NULL) 1158 { 1159#ifdef CALL_TRACE 1160 fprintf(stderr, "** %s can't find worklist item\n", __func__); 1161#endif 1162 return; 1163 } 1164 1165#ifdef CALL_TRACE 1166 fprintf(stderr, "** %s worklist item %p flags are 0x%08x\n", __func__, r, r->flags); 1167#endif 1168 if ((r->flags & WORKUNIT_CANCELLED) == 0) 1169 { 1170#ifdef CALL_TRACE 1171 fprintf(stderr, "** %s workunit thread is still active\n", __func__); 1172#endif 1173 return; 1174 } 1175 1176 if (r->callback != NULL) 1177 { 1178 if (r->flags & WORKUNIT_RETURNS_LIST) ((list_async_callback)(r->callback))(r->reslist, r->err, r->context); 1179 else ((item_async_callback)(r->callback))(r->resitem, r->err, r->context); 1180 1181 r->reslist = NULL; 1182 r->resitem = NULL; 1183 } 1184 else 1185 { 1186#ifdef CALL_TRACE 1187 fprintf(stderr, "** %s workunit has no callback\n", __func__); 1188#endif 1189 } 1190 1191 si_async_workunit_release(r); 1192} 1193 1194char * 1195si_standardize_mac_address(const char *addr) 1196{ 1197 char e[6][3]; 1198 char *out; 1199 struct ether_addr *ether; 1200 int i; 1201 1202 if (addr == NULL) return NULL; 1203 1204 /* ether_aton isn't thread-safe */ 1205 pthread_mutex_lock(&module_mutex); 1206 1207 ether = ether_aton(addr); 1208 if (ether == NULL) 1209 { 1210 pthread_mutex_unlock(&module_mutex); 1211 return NULL; 1212 } 1213 1214 for (i = 0; i < 6; i++) 1215 { 1216 if (ether->ether_addr_octet[i] <= 15) 1217 { 1218 sprintf(e[i], "0%x", ether->ether_addr_octet[i]); 1219 } 1220 else 1221 { 1222 sprintf(e[i], "%x", ether->ether_addr_octet[i]); 1223 } 1224 } 1225 1226 pthread_mutex_unlock(&module_mutex); 1227 1228 out = NULL; 1229 asprintf(&out, "%s:%s:%s:%s:%s:%s", e[0], e[1], e[2], e[3], e[4], e[5]); 1230 return out; 1231} 1232