1/* 2 * Copyright (c) 2003-2010 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 <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <asl.h> 28#include <bsm/libbsm.h> 29#include <mach/mach.h> 30#include <mach/mach_error.h> 31#include <mach/mach_traps.h> 32#include <sys/sysctl.h> 33#include <pthread.h> 34#include <sys/fcntl.h> 35#include <dispatch/private.h> 36#include "notify.h" 37#include "notifyd.h" 38#include "service.h" 39#include "notify_ipc.h" 40#include "notify_ipcServer.h" 41 42static void 43cancel_subscription(client_t *c) 44{ 45 name_info_t *n; 46 int token; 47 48 if (global.notify_state == NULL) return; 49 if (c == NULL) return; 50 51 call_statistics.cleanup++; 52 53 token = c->client_id; 54 55 if (c->private != NULL) 56 { 57 service_close(c->private); 58 c->private = NULL; 59 } 60 61 n = c->name_info; 62 if ((n != NULL) && (n->refcount == 1) && (n->private != NULL)) 63 { 64 service_close(n->private); 65 n->private = NULL; 66 } 67 68 _notify_lib_port_proc_release(global.notify_state, MACH_PORT_NULL, c->pid); 69 70 if (c->notify_type == NOTIFY_TYPE_MEMORY) 71 { 72 global.shared_memory_refcount[n->slot]--; 73 } 74 else if (c->notify_type == NOTIFY_TYPE_PORT) 75 { 76 _notify_lib_port_proc_release(global.notify_state, c->port, 0); 77 } 78 79 _notify_lib_cancel(global.notify_state, c->pid, token); 80} 81 82static void 83cancel_proc(void *px) 84{ 85 void *tt; 86 long lpid = (long)px; 87 pid_t pid; 88 client_t *c; 89 list_t *l, *x; 90 91 if (global.notify_state == NULL) return; 92 93 pid = lpid; 94 x = NULL; 95 96 tt = _nc_table_traverse_start(global.notify_state->client_table); 97 while (tt != NULL) 98 { 99 c = _nc_table_traverse(global.notify_state->client_table, tt); 100 if (c == NULL) break; 101 102 if (c->pid == pid) x = _nc_list_prepend(x, _nc_list_new(c)); 103 } 104 _nc_table_traverse_end(global.notify_state->client_table, tt); 105 106 for (l = x; l != NULL; l = _nc_list_next(l)) 107 { 108 c = _nc_list_data(l); 109 cancel_subscription(c); 110 } 111 112 _nc_list_release_list(x); 113} 114 115static void 116cancel_port(mach_port_t port, dispatch_source_t src) 117{ 118 void *tt; 119 client_t *c; 120 list_t *l, *x; 121 122 if (global.notify_state == NULL) return; 123 124 x = NULL; 125 126 tt = _nc_table_traverse_start(global.notify_state->client_table); 127 while (tt != NULL) 128 { 129 c = _nc_table_traverse(global.notify_state->client_table, tt); 130 if (c == NULL) break; 131 132 if (c->port == port) x = _nc_list_prepend(x, _nc_list_new(c)); 133 } 134 _nc_table_traverse_end(global.notify_state->client_table, tt); 135 136 for (l = x; l != NULL; l = _nc_list_next(l)) 137 { 138 c = _nc_list_data(l); 139 cancel_subscription(c); 140 } 141 142 _nc_list_release_list(x); 143} 144 145static void 146port_event(void *px) 147{ 148 long lport = (long)px; 149 mach_port_t port; 150 unsigned long data; 151 portproc_data_t *pp; 152 153 if (global.notify_state == NULL) return; 154 155 port = (mach_port_t)lport; 156 if (port == MACH_PORT_NULL) return; 157 158 pp = _notify_lib_port_proc_find(global.notify_state, port, 0); 159 if (pp == NULL) 160 { 161 log_message(ASL_LEVEL_DEBUG, "can't find port source for %u\n", port); 162 return; 163 } 164 165 data = dispatch_source_get_data(pp->src); 166 167 if (data & DISPATCH_MACH_SEND_DEAD) 168 { 169 cancel_port(port, pp->src); 170 } 171 else if (data & DISPATCH_MACH_SEND_POSSIBLE) 172 { 173 _notify_lib_resume_port(global.notify_state, port); 174 } 175 else 176 { 177 log_message(ASL_LEVEL_DEBUG, "unknown data 0x%lx for %u\n", data, port); 178 } 179 180 _notify_lib_port_proc_release(global.notify_state, port, 0); 181} 182 183static void 184port_dealloc(void *px) 185{ 186 long lport = (long)px; 187 mach_port_t port = (mach_port_t)lport; 188 189 if (port == MACH_PORT_NULL) return; 190 mach_port_deallocate(mach_task_self(), port); 191} 192 193static void 194port_registration_complete(void *px) 195{ 196 long lport = (long)px; 197 mach_port_t port; 198 199 if (global.notify_state == NULL) return; 200 201 port = (mach_port_t)lport; 202 _notify_lib_resume_port(global.notify_state, port); 203} 204 205static void 206register_pid(pid_t pid) 207{ 208 dispatch_source_t src; 209 long lpid; 210 portproc_data_t *pp; 211 212 if (global.notify_state == NULL) return; 213 if (pid <= 0) return; 214 215 /* 216 * Check if this pid has already registered. 217 * N.B. This call retains the portproc_data_t. We want that. 218 */ 219 pp = _notify_lib_port_proc_find(global.notify_state, MACH_PORT_NULL, pid); 220 if (pp != NULL) return; 221 222 src = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, pid, DISPATCH_PROC_EXIT, global.work_q); 223 dispatch_source_set_event_handler_f(src, (dispatch_function_t)cancel_proc); 224 225 lpid = pid; 226 dispatch_set_context(src, (void *)lpid); 227 228 _notify_lib_port_proc_new(global.notify_state, MACH_PORT_NULL, pid, 0, src); 229 230 dispatch_resume(src); 231} 232 233static void 234register_port(client_t *c) 235{ 236 dispatch_source_t src; 237 long lport; 238 portproc_data_t *pp; 239 240 if (c == NULL) return; 241 242 /* ignore MACH_PORT_DEAD */ 243 if (c->port == MACH_PORT_DEAD) return; 244 245 /* 246 * Check if this port has already registered. 247 * N.B. This call retains the portproc_data_t. We want that. 248 */ 249 pp = _notify_lib_port_proc_find(global.notify_state, c->port, 0); 250 if (pp != NULL) return; 251 252 src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, c->port, DISPATCH_MACH_SEND_DEAD | DISPATCH_MACH_SEND_POSSIBLE, global.work_q); 253 254 dispatch_source_set_event_handler_f(src, (dispatch_function_t)port_event); 255 256 /* retain send right for port - port_dealloc() will release when the source goes away */ 257 mach_port_mod_refs(mach_task_self(), c->port, MACH_PORT_RIGHT_SEND, +1); 258 dispatch_source_set_cancel_handler_f(src, (dispatch_function_t)port_dealloc); 259 260 lport = c->port; 261 dispatch_set_context(src, (void *)lport); 262 263 dispatch_source_set_registration_handler_f(src, (dispatch_function_t)port_registration_complete); 264 265 _notify_lib_port_proc_new(global.notify_state, c->port, 0, NOTIFY_PORT_PROC_STATE_SUSPENDED, src); 266 267 dispatch_resume(src); 268} 269 270static uint32_t 271server_preflight(caddr_t name, mach_msg_type_number_t nameCnt, audit_token_t audit, int token, uid_t *uid, gid_t *gid, pid_t *pid, uint64_t *cid) 272{ 273 pid_t xpid; 274 275 if ((name == NULL) && (nameCnt != 0)) return NOTIFY_STATUS_INVALID_NAME; 276 277 if (global.notify_state == NULL) 278 { 279 if (name != NULL) vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 280 return NOTIFY_STATUS_FAILED; 281 } 282 283 if ((name != NULL) && (name[nameCnt] != '\0')) 284 { 285 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 286 return NOTIFY_STATUS_INVALID_NAME; 287 } 288 289 audit_token_to_au32(audit, NULL, uid, gid, NULL, NULL, &xpid, NULL, NULL); 290 if (pid != NULL) *pid = xpid; 291 292 if (token > 0) 293 { 294 client_t *c; 295 uint64_t xcid = make_client_id(xpid, token); 296 if (cid != NULL) *cid = xcid; 297 298 c = _nc_table_find_64(global.notify_state->client_table, xcid); 299 if (c != NULL) 300 { 301 /* duplicate tokens can occur if a process exec()s */ 302 log_message(ASL_LEVEL_DEBUG, "duplicate token %d sent from PID %d\n", token, xpid); 303 cancel_subscription(c); 304 } 305 } 306 307 return NOTIFY_STATUS_OK; 308} 309 310kern_return_t __notify_server_post_3 311( 312 mach_port_t server, 313 uint64_t name_id, 314 audit_token_t audit 315) 316{ 317 uid_t uid = (uid_t)-1; 318 gid_t gid = (gid_t)-1; 319 320 if (global.notify_state == NULL) return KERN_SUCCESS; 321 322 call_statistics.post++; 323 call_statistics.post_by_id++; 324 325 log_message(ASL_LEVEL_DEBUG, "__notify_server_post name_id %llu\n", name_id); 326 327 audit_token_to_au32(audit, NULL, &uid, &gid, NULL, NULL, NULL, NULL, NULL); 328 329 daemon_post_nid(name_id, uid, gid); 330 return KERN_SUCCESS; 331} 332 333kern_return_t __notify_server_post_2 334( 335 mach_port_t server, 336 caddr_t name, 337 mach_msg_type_number_t nameCnt, 338 uint64_t *name_id, 339 int *status, 340 audit_token_t audit 341) 342{ 343 uid_t uid = (uid_t)-1; 344 gid_t gid = (gid_t)-1; 345 name_info_t *n; 346 347 *status = server_preflight(name, nameCnt, audit, -1, &uid, &gid, NULL, NULL); 348 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 349 350 call_statistics.post++; 351 call_statistics.post_by_name_and_fetch_id++; 352 353 *status = _notify_lib_check_controlled_access(global.notify_state, name, uid, gid, NOTIFY_ACCESS_WRITE); 354 if (*status != NOTIFY_STATUS_OK) 355 { 356 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 357 return KERN_SUCCESS; 358 } 359 360 n = NULL; 361 *status = daemon_post(name, uid, gid); 362 if (*status == NOTIFY_STATUS_OK) 363 { 364 n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 365 } 366 367 if (n == NULL) 368 { 369 *status = NOTIFY_STATUS_INVALID_NAME; 370 *name_id = UINT64_MAX; 371 call_statistics.post_no_op++; 372 } 373 else 374 { 375 *name_id = n->name_id; 376 } 377 378 if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s\n", name); 379 else log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s [%llu]\n", name, *name_id); 380 381 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 382 383 return KERN_SUCCESS; 384} 385 386kern_return_t __notify_server_post_4 387( 388 mach_port_t server, 389 caddr_t name, 390 mach_msg_type_number_t nameCnt, 391 audit_token_t audit 392) 393{ 394 uint64_t ignored_name_id; 395 int ignored_status; 396 kern_return_t kstatus; 397 398 kstatus = __notify_server_post_2(server, name, nameCnt, &ignored_name_id, &ignored_status, audit); 399 400 call_statistics.post_by_name_and_fetch_id--; 401 call_statistics.post_by_name++; 402 403 return kstatus; 404} 405 406kern_return_t __notify_server_post 407( 408 mach_port_t server, 409 caddr_t name, 410 mach_msg_type_number_t nameCnt, 411 int *status, 412 audit_token_t audit 413) 414{ 415 uint64_t ignored_name_id; 416 kern_return_t kstatus; 417 418 kstatus = __notify_server_post_2(server, name, nameCnt, &ignored_name_id, status, audit); 419 420 call_statistics.post_by_name_and_fetch_id--; 421 call_statistics.post_by_name++; 422 423 if (*status == NOTIFY_STATUS_INVALID_NAME) *status = NOTIFY_STATUS_OK; 424 425 return kstatus; 426} 427 428kern_return_t __notify_server_register_plain_2 429( 430 mach_port_t server, 431 caddr_t name, 432 mach_msg_type_number_t nameCnt, 433 int token, 434 audit_token_t audit 435) 436{ 437 client_t *c; 438 uint64_t nid, cid; 439 uint32_t status; 440 uid_t uid = (uid_t)-1; 441 gid_t gid = (gid_t)-1; 442 pid_t pid = (pid_t)-1; 443 444 call_statistics.reg++; 445 call_statistics.reg_plain++; 446 447 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 448 if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 449 450 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_plain %s %d %d\n", name, pid, token); 451 452 status = _notify_lib_register_plain(global.notify_state, name, pid, token, -1, uid, gid, &nid); 453 if (status != NOTIFY_STATUS_OK) 454 { 455 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 456 return KERN_SUCCESS; 457 } 458 459 c = _nc_table_find_64(global.notify_state->client_table, cid); 460 461 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 462 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 463 464 register_pid(pid); 465 466 return KERN_SUCCESS; 467} 468 469kern_return_t __notify_server_register_check_2 470( 471 mach_port_t server, 472 caddr_t name, 473 mach_msg_type_number_t nameCnt, 474 int token, 475 int *size, 476 int *slot, 477 uint64_t *name_id, 478 int *status, 479 audit_token_t audit 480) 481{ 482 name_info_t *n; 483 uint32_t i, j, x, new_slot; 484 uint64_t cid; 485 client_t *c; 486 uid_t uid = (uid_t)-1; 487 gid_t gid = (gid_t)-1; 488 pid_t pid = (pid_t)-1; 489 490 *size = 0; 491 *slot = 0; 492 493 *status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 494 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 495 496 call_statistics.reg++; 497 call_statistics.reg_check++; 498 499 if (global.nslots == 0) 500 { 501 *size = -1; 502 *slot = -1; 503 return __notify_server_register_plain_2(server, name, nameCnt, token, audit); 504 } 505 506 x = (uint32_t)-1; 507 508 n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 509 if (n != NULL) x = n->slot; 510 511 new_slot = 0; 512 if (x == (uint32_t)-1) 513 { 514 /* find a slot */ 515 new_slot = 1; 516 517 /* 518 * Check slots beginning at the current slot_id + 1, since it's likely that the 519 * next slot will be available. Keep looking until we have examined all the 520 * slots (skipping slot 0, which is reserved for notifyd). Stop if we find 521 * an unused (refcount == 0) slot. 522 */ 523 for (i = 1, j = global.slot_id + 1; i < global.nslots; i++, j++) 524 { 525 if (j >= global.nslots) j = 1; 526 if (global.shared_memory_refcount[j] == 0) 527 { 528 x = j; 529 break; 530 } 531 } 532 533 if (x == (uint32_t)-1) 534 { 535 /* 536 * We did not find an unused slot. At this point, the shared 537 * memory table is full, so we start re-using slots, beginning at 538 * global.slot_id + 1. 539 */ 540 global.slot_id++; 541 542 /* wrap around to slot 1 (slot 0 is reserved for notifyd) */ 543 if (global.slot_id >= global.nslots) global.slot_id = 1; 544 log_message(ASL_LEVEL_DEBUG, "reused shared memory slot %u\n", global.slot_id); 545 x = global.slot_id; 546 } 547 else 548 { 549 /* found a free slot */ 550 global.slot_id = x; 551 } 552 } 553 554 if (new_slot == 1) global.shared_memory_base[x] = 1; 555 global.shared_memory_refcount[x]++; 556 557 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_check %s %d %d\n", name, pid, token); 558 559 *size = global.nslots * sizeof(uint32_t); 560 *slot = x; 561 *status = _notify_lib_register_plain(global.notify_state, name, pid, token, x, uid, gid, name_id); 562 if (*status != NOTIFY_STATUS_OK) 563 { 564 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 565 return KERN_SUCCESS; 566 } 567 568 c = _nc_table_find_64(global.notify_state->client_table, cid); 569 570 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 571 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 572 573 register_pid(pid); 574 575 return KERN_SUCCESS; 576} 577 578kern_return_t __notify_server_register_signal_2 579( 580 mach_port_t server, 581 caddr_t name, 582 mach_msg_type_number_t nameCnt, 583 int token, 584 int sig, 585 audit_token_t audit 586) 587{ 588 client_t *c; 589 uint64_t name_id, cid; 590 uint32_t status; 591 uid_t uid = (uid_t)-1; 592 gid_t gid = (gid_t)-1; 593 pid_t pid = (pid_t)-1; 594 595 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 596 if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 597 598 call_statistics.reg++; 599 call_statistics.reg_signal++; 600 601 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_signal %s %d %d %d\n", name, pid, token, sig); 602 603 status = _notify_lib_register_signal(global.notify_state, name, pid, token, sig, uid, gid, &name_id); 604 if (status != NOTIFY_STATUS_OK) 605 { 606 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 607 return KERN_SUCCESS; 608 } 609 610 c = _nc_table_find_64(global.notify_state->client_table, cid); 611 612 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 613 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 614 615 register_pid(pid); 616 617 return KERN_SUCCESS; 618} 619 620kern_return_t __notify_server_register_file_descriptor_2 621( 622 mach_port_t server, 623 caddr_t name, 624 mach_msg_type_number_t nameCnt, 625 int token, 626 fileport_t fileport, 627 audit_token_t audit 628) 629{ 630 client_t *c; 631 int fd, flags; 632 uint32_t status; 633 uint64_t name_id, cid; 634 uid_t uid = (uid_t)-1; 635 gid_t gid = (gid_t)-1; 636 pid_t pid = (pid_t)-1; 637 638 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 639 if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 640 641 call_statistics.reg++; 642 call_statistics.reg_file++; 643 644 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_file_descriptor %s %d %d\n", name, pid, token); 645 646 fd = fileport_makefd(fileport); 647 mach_port_deallocate(mach_task_self(), fileport); 648 if (fd < 0) 649 { 650 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 651 return KERN_SUCCESS; 652 } 653 654 flags = fcntl(fd, F_GETFL, 0); 655 if (flags < 0) 656 { 657 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 658 return KERN_SUCCESS; 659 } 660 661 flags |= O_NONBLOCK; 662 if (fcntl(fd, F_SETFL, flags) < 0) 663 { 664 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 665 return KERN_SUCCESS; 666 } 667 668 status = _notify_lib_register_file_descriptor(global.notify_state, name, pid, token, fd, uid, gid, &name_id); 669 if (status != NOTIFY_STATUS_OK) 670 { 671 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 672 return KERN_SUCCESS; 673 } 674 675 c = _nc_table_find_64(global.notify_state->client_table, cid); 676 677 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 678 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 679 680 register_pid(pid); 681 682 return KERN_SUCCESS; 683} 684 685kern_return_t __notify_server_register_mach_port_2 686( 687 mach_port_t server, 688 caddr_t name, 689 mach_msg_type_number_t nameCnt, 690 int token, 691 mach_port_t port, 692 audit_token_t audit 693) 694{ 695 client_t *c; 696 uint64_t name_id, cid; 697 uint32_t status; 698 uid_t uid = (uid_t)-1; 699 gid_t gid = (gid_t)-1; 700 pid_t pid = (pid_t)-1; 701 702 if (port == MACH_PORT_DEAD) return KERN_SUCCESS; 703 704 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 705 if (status != NOTIFY_STATUS_OK) 706 { 707 mach_port_deallocate(mach_task_self(), port); 708 return KERN_SUCCESS; 709 } 710 711 call_statistics.reg++; 712 call_statistics.reg_port++; 713 714 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_mach_port %s %d %d\n", name, pid, token); 715 716 status = _notify_lib_register_mach_port(global.notify_state, name, pid, token, port, uid, gid, &name_id); 717 if (status != NOTIFY_STATUS_OK) 718 { 719 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 720 mach_port_deallocate(mach_task_self(), port); 721 return KERN_SUCCESS; 722 } 723 724 c = _nc_table_find_64(global.notify_state->client_table,cid); 725 726#ifdef PORT_DEBUG 727 log_message(ASL_LEVEL_NOTICE, "register com port 0x%08x for pid %d\n", port, pid); 728#endif 729 730 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 731 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 732 733 register_pid(pid); 734 register_port(c); 735 736 return KERN_SUCCESS; 737} 738 739kern_return_t __notify_server_cancel 740( 741 mach_port_t server, 742 int token, 743 int *status, 744 audit_token_t audit 745) 746{ 747 client_t *c; 748 uid_t uid = (uid_t)-1; 749 pid_t pid = (pid_t)-1; 750 751 *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, &pid, NULL); 752 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 753 754 call_statistics.cancel++; 755 756 log_message(ASL_LEVEL_DEBUG, "__notify_server_cancel %d %d\n", pid, token); 757 758 *status = NOTIFY_STATUS_OK; 759 760 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 761 if (c == NULL) *status = NOTIFY_STATUS_FAILED; 762 else cancel_subscription(c); 763 764 return KERN_SUCCESS; 765} 766 767kern_return_t __notify_server_cancel_2 768( 769 mach_port_t server, 770 int token, 771 audit_token_t audit 772) 773{ 774 int ignored; 775 return __notify_server_cancel(server, token, &ignored, audit); 776} 777 778kern_return_t __notify_server_suspend 779( 780 mach_port_t server, 781 int token, 782 int *status, 783 audit_token_t audit 784) 785{ 786 pid_t pid = (pid_t)-1; 787 788 *status = server_preflight(NULL, 0, audit, -1, NULL, NULL, &pid, NULL); 789 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 790 791 call_statistics.suspend++; 792 793 log_message(ASL_LEVEL_DEBUG, "__notify_server_suspend %d %d\n", pid, token); 794 795 _notify_lib_suspend(global.notify_state, pid, token); 796 *status = NOTIFY_STATUS_OK; 797 798 return KERN_SUCCESS; 799} 800 801kern_return_t __notify_server_resume 802( 803 mach_port_t server, 804 int token, 805 int *status, 806 audit_token_t audit 807) 808{ 809 pid_t pid = (pid_t)-1; 810 811 *status = server_preflight(NULL, 0, audit, -1, NULL, NULL, &pid, NULL); 812 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 813 814 call_statistics.resume++; 815 816 log_message(ASL_LEVEL_DEBUG, "__notify_server_resume %d %d\n", pid, token); 817 818 _notify_lib_resume(global.notify_state, pid, token); 819 *status = NOTIFY_STATUS_OK; 820 821 return KERN_SUCCESS; 822} 823 824static uid_t 825uid_for_pid(pid_t pid) 826{ 827 int mib[4]; 828 struct kinfo_proc info; 829 size_t size = sizeof(struct kinfo_proc); 830 831 mib[0] = CTL_KERN; 832 mib[1] = KERN_PROC; 833 mib[2] = KERN_PROC_PID; 834 mib[3] = pid; 835 836 sysctl(mib, 4, &info, &size, 0, 0); 837 838 return (uid_t)info.kp_eproc.e_ucred.cr_uid; 839} 840 841kern_return_t __notify_server_suspend_pid 842( 843 mach_port_t server, 844 int pid, 845 int *status, 846 audit_token_t audit 847) 848{ 849 uid_t uid, target_uid; 850 851 uid = (uid_t)-1; 852 853 *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, NULL, NULL); 854 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 855 856 call_statistics.suspend_pid++; 857 858 log_message(ASL_LEVEL_DEBUG, "__notify_server_suspend_pid %d\n", pid); 859 860 target_uid = uid_for_pid(pid); 861 862 if ((uid != 0) && (target_uid != uid)) 863 { 864 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 865 return KERN_SUCCESS; 866 } 867 868 *status = NOTIFY_STATUS_OK; 869 870 _notify_lib_suspend_proc(global.notify_state, pid); 871 872 return KERN_SUCCESS; 873} 874 875kern_return_t __notify_server_resume_pid 876( 877 mach_port_t server, 878 int pid, 879 int *status, 880 audit_token_t audit 881) 882{ 883 uid_t uid, target_uid; 884 885 uid = (uid_t)-1; 886 887 *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, NULL, NULL); 888 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 889 890 call_statistics.resume_pid++; 891 892 log_message(ASL_LEVEL_DEBUG, "__notify_server_resume_pid %d\n", pid); 893 894 target_uid = uid_for_pid(pid); 895 896 if ((uid != 0) && (target_uid != uid)) 897 { 898 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 899 return KERN_SUCCESS; 900 } 901 902 *status = NOTIFY_STATUS_OK; 903 904 _notify_lib_resume_proc(global.notify_state, pid); 905 906 return KERN_SUCCESS; 907} 908 909kern_return_t __notify_server_check 910( 911 mach_port_t server, 912 int token, 913 int *check, 914 int *status, 915 audit_token_t audit 916) 917{ 918 pid_t pid = (gid_t)-1; 919 920 call_statistics.check++; 921 922 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 923 924 log_message(ASL_LEVEL_DEBUG, "__notify_server_check %d %d\n", pid, token); 925 926 *status = _notify_lib_check(global.notify_state, pid, token, check); 927 return KERN_SUCCESS; 928} 929 930kern_return_t __notify_server_get_state 931( 932 mach_port_t server, 933 int token, 934 uint64_t *state, 935 int *status, 936 audit_token_t audit 937) 938{ 939 uid_t uid = (uid_t)-1; 940 gid_t gid = (gid_t)-1; 941 pid_t pid = (pid_t)-1; 942 client_t *c; 943 944 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 945 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 946 947 call_statistics.get_state++; 948 call_statistics.get_state_by_client++; 949 950 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state %d %d\n", pid, token); 951 952 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 953 if ((c == NULL) || (c->name_info == NULL)) 954 { 955 *status = NOTIFY_STATUS_FAILED; 956 } 957 else 958 { 959 *status = _notify_lib_get_state(global.notify_state, c->name_info->name_id, state, uid, gid); 960 } 961 962 return KERN_SUCCESS; 963} 964 965kern_return_t __notify_server_get_state_2 966( 967 mach_port_t server, 968 uint64_t name_id, 969 uint64_t *state, 970 int *status, 971 audit_token_t audit 972) 973{ 974 uid_t uid = (uid_t)-1; 975 gid_t gid = (gid_t)-1; 976 977 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, NULL, NULL); 978 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 979 980 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_2 %llu\n", name_id); 981 982 *status = _notify_lib_get_state(global.notify_state, name_id, state, uid, gid); 983 return KERN_SUCCESS; 984} 985 986kern_return_t __notify_server_get_state_3 987( 988 mach_port_t server, 989 int token, 990 uint64_t *state, 991 uint64_t *name_id, 992 int *status, 993 audit_token_t audit 994) 995{ 996 uid_t uid = (uid_t)-1; 997 gid_t gid = (gid_t)-1; 998 pid_t pid = (pid_t)-1; 999 client_t *c; 1000 1001 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 1002 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1003 1004 call_statistics.get_state++; 1005 call_statistics.get_state_by_client_and_fetch_id++; 1006 1007 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1008 if ((c == NULL) || (c->name_info == NULL)) 1009 { 1010 *status = NOTIFY_STATUS_FAILED; 1011 *name_id = UINT64_MAX; 1012 } 1013 else 1014 { 1015 *status = _notify_lib_get_state(global.notify_state, c->name_info->name_id, state, uid, gid); 1016 *name_id = c->name_info->name_id; 1017 } 1018 1019 if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_3 %d %d\n", pid, token); 1020 else log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_3 %d %d [%llu]\n", pid, token, *name_id); 1021 1022 return KERN_SUCCESS; 1023} 1024 1025kern_return_t __notify_server_set_state_3 1026( 1027 mach_port_t server, 1028 int token, 1029 uint64_t state, 1030 uint64_t *name_id, 1031 int *status, 1032 audit_token_t audit 1033) 1034{ 1035 client_t *c; 1036 uid_t uid = (uid_t)-1; 1037 gid_t gid = (gid_t)-1; 1038 pid_t pid = (pid_t)-1; 1039 1040 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 1041 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1042 1043 call_statistics.set_state++; 1044 call_statistics.set_state_by_client_and_fetch_id++; 1045 1046 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1047 if ((c == NULL) || (c->name_info == NULL)) 1048 { 1049 *status = NOTIFY_STATUS_FAILED; 1050 *name_id = UINT64_MAX; 1051 } 1052 else 1053 { 1054 *status = _notify_lib_set_state(global.notify_state, c->name_info->name_id, state, uid, gid); 1055 *name_id = c->name_info->name_id; 1056 } 1057 1058 if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_3 %d %d %llu\n", pid, token, state); 1059 else log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_3 %d %d %llu [%llu]\n", pid, token, state, *name_id); 1060 1061 return KERN_SUCCESS; 1062} 1063 1064kern_return_t __notify_server_set_state 1065( 1066 mach_port_t server, 1067 int token, 1068 uint64_t state, 1069 int *status, 1070 audit_token_t audit 1071) 1072{ 1073 uint64_t ignored; 1074 kern_return_t kstatus; 1075 1076 kstatus = __notify_server_set_state_3(server, token, state, &ignored, status, audit); 1077 1078 call_statistics.set_state_by_client_and_fetch_id--; 1079 call_statistics.set_state_by_client++; 1080 1081 return kstatus; 1082} 1083 1084kern_return_t __notify_server_set_state_2 1085( 1086 mach_port_t server, 1087 uint64_t name_id, 1088 uint64_t state, 1089 audit_token_t audit 1090) 1091{ 1092 uint32_t status; 1093 uid_t uid = (uid_t)-1; 1094 gid_t gid = (gid_t)-1; 1095 1096 if (global.notify_state == NULL) return KERN_SUCCESS; 1097 1098 call_statistics.set_state++; 1099 call_statistics.set_state_by_id++; 1100 1101 audit_token_to_au32(audit, NULL, &uid, &gid, NULL, NULL, NULL, NULL, NULL); 1102 1103 log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_2 %llu %llu\n", name_id, state); 1104 1105 status = _notify_lib_set_state(global.notify_state, name_id, state, uid, gid); 1106 return KERN_SUCCESS; 1107} 1108 1109kern_return_t __notify_server_set_owner 1110( 1111 mach_port_t server, 1112 caddr_t name, 1113 mach_msg_type_number_t nameCnt, 1114 int uid, 1115 int gid, 1116 int *status, 1117 audit_token_t audit 1118) 1119{ 1120 uid_t auid = (uid_t)-1; 1121 1122 *status = server_preflight(name, nameCnt, audit, -1, &auid, NULL, NULL, NULL); 1123 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1124 1125 call_statistics.set_owner++; 1126 1127 log_message(ASL_LEVEL_DEBUG, "__notify_server_set_owner %s %d %d\n", name, uid, gid); 1128 1129 /* only root may set owner for names */ 1130 if (auid != 0) 1131 { 1132 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1133 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 1134 return KERN_SUCCESS; 1135 } 1136 1137 *status = _notify_lib_set_owner(global.notify_state, name, uid, gid); 1138 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1139 return KERN_SUCCESS; 1140} 1141 1142kern_return_t __notify_server_get_owner 1143( 1144 mach_port_t server, 1145 caddr_t name, 1146 mach_msg_type_number_t nameCnt, 1147 int *uid, 1148 int *gid, 1149 int *status, 1150 audit_token_t audit 1151) 1152{ 1153 *status = server_preflight(name, nameCnt, audit, -1, NULL, NULL, NULL, NULL); 1154 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1155 1156 call_statistics.get_owner++; 1157 1158 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_owner %s\n", name); 1159 1160 *status = _notify_lib_get_owner(global.notify_state, name, (uint32_t *)uid, (uint32_t *)gid); 1161 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1162 return KERN_SUCCESS; 1163} 1164 1165kern_return_t __notify_server_set_access 1166( 1167 mach_port_t server, 1168 caddr_t name, 1169 mach_msg_type_number_t nameCnt, 1170 int mode, 1171 int *status, 1172 audit_token_t audit 1173) 1174{ 1175 uint32_t u, g; 1176 uid_t uid = (uid_t)-1; 1177 gid_t gid = (gid_t)-1; 1178 1179 *status = server_preflight(name, nameCnt, audit, -1, &uid, &gid, NULL, NULL); 1180 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1181 1182 call_statistics.set_access++; 1183 1184 log_message(ASL_LEVEL_DEBUG, "__notify_server_set_access %s 0x%03x\n", name, mode); 1185 1186 _notify_lib_get_owner(global.notify_state, name, &u, &g); 1187 1188 /* only root and owner may set access for names */ 1189 if ((uid != 0) && (uid != u)) 1190 { 1191 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 1192 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1193 return KERN_SUCCESS; 1194 } 1195 1196 *status = _notify_lib_set_access(global.notify_state, name, mode); 1197 if ((u != 0) || (g != 0)) *status = _notify_lib_set_owner(global.notify_state, name, u, g); 1198 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1199 return KERN_SUCCESS; 1200} 1201 1202kern_return_t __notify_server_get_access 1203( 1204 mach_port_t server, 1205 caddr_t name, 1206 mach_msg_type_number_t nameCnt, 1207 int *mode, 1208 int *status, 1209 audit_token_t audit 1210) 1211{ 1212 *status = server_preflight(name, nameCnt, audit, -1, NULL, NULL, NULL, NULL); 1213 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1214 1215 call_statistics.get_access++; 1216 1217 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_access %s\n", name); 1218 1219 *status = _notify_lib_get_access(global.notify_state, name, (uint32_t *)mode); 1220 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1221 return KERN_SUCCESS; 1222} 1223 1224/* Unsupported because it makes no sense */ 1225kern_return_t __notify_server_release_name 1226( 1227 mach_port_t server, 1228 caddr_t name, 1229 mach_msg_type_number_t nameCnt, 1230 int *status, 1231 audit_token_t audit 1232) 1233{ 1234 *status = NOTIFY_STATUS_FAILED; 1235 return KERN_SUCCESS; 1236} 1237 1238kern_return_t __notify_server_monitor_file 1239( 1240 mach_port_t server, 1241 int token, 1242 caddr_t path, 1243 mach_msg_type_number_t pathCnt, 1244 int flags, 1245 int *status, 1246 audit_token_t audit 1247) 1248{ 1249 client_t *c; 1250 name_info_t *n; 1251 uid_t uid = (uid_t)-1; 1252 gid_t gid = (gid_t)-1; 1253 pid_t pid = (pid_t)-1; 1254 uint32_t ubits = (uint32_t)flags; 1255 1256 *status = server_preflight(path, pathCnt, audit, -1, &uid, &gid, &pid, NULL); 1257 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1258 1259 call_statistics.monitor_file++; 1260 1261 log_message(ASL_LEVEL_DEBUG, "__notify_server_monitor_file %d %d %s 0x%08x\n", pid, token, path, ubits); 1262 1263 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1264 if (c == NULL) 1265 { 1266 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1267 *status = NOTIFY_STATUS_INVALID_REQUEST; 1268 return KERN_SUCCESS; 1269 } 1270 1271 n = c->name_info; 1272 if (n == NULL) 1273 { 1274 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1275 *status = NOTIFY_STATUS_INVALID_REQUEST; 1276 return KERN_SUCCESS; 1277 } 1278 1279 *status = service_open_path_private(n->name, c, path, uid, gid, ubits); 1280 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1281 1282 return KERN_SUCCESS; 1283} 1284 1285kern_return_t __notify_server_monitor_file_2 1286( 1287 mach_port_t server, 1288 int token, 1289 caddr_t path, 1290 mach_msg_type_number_t pathCnt, 1291 int flags, 1292 audit_token_t audit 1293) 1294{ 1295 int ignored; 1296 return __notify_server_monitor_file(server, token, path, pathCnt, flags, &ignored, audit); 1297} 1298 1299/* 1300 * Original routines provide compatibility for legacy clients. 1301 * iOS simulator uses them. 1302 */ 1303 1304/* 1305 * Generates a integer "token" for legacy client registrations. 1306 */ 1307static int 1308generate_token(audit_token_t audit) 1309{ 1310 static int legacy_id = 0; 1311 1312 if (++legacy_id == -1) legacy_id = 1; 1313 return legacy_id; 1314} 1315 1316kern_return_t __notify_server_register_plain 1317( 1318 mach_port_t server, 1319 caddr_t name, 1320 mach_msg_type_number_t nameCnt, 1321 int *client_id, 1322 int *status, 1323 audit_token_t audit 1324) 1325{ 1326 int token = generate_token(audit); 1327 1328 *client_id = token; 1329 *status = NOTIFY_STATUS_OK; 1330 1331 return __notify_server_register_plain_2(server, name, nameCnt, token, audit); 1332} 1333 1334kern_return_t __notify_server_register_check 1335( 1336 mach_port_t server, 1337 caddr_t name, 1338 mach_msg_type_number_t nameCnt, 1339 int *size, 1340 int *slot, 1341 int *client_id, 1342 int *status, 1343 audit_token_t audit 1344) 1345{ 1346 uint64_t nid; 1347 int token = generate_token(audit); 1348 1349 *client_id = token; 1350 1351 return __notify_server_register_check_2(server, name, nameCnt, token, size, slot, &nid, status, audit); 1352} 1353 1354kern_return_t __notify_server_register_signal 1355( 1356 mach_port_t server, 1357 caddr_t name, 1358 mach_msg_type_number_t nameCnt, 1359 int sig, 1360 int *client_id, 1361 int *status, 1362 audit_token_t audit 1363) 1364{ 1365 int token = generate_token(audit); 1366 1367 *client_id = token; 1368 *status = NOTIFY_STATUS_OK; 1369 1370 return __notify_server_register_signal_2(server, name, nameCnt, token, sig, audit); 1371} 1372 1373kern_return_t __notify_server_register_file_descriptor 1374( 1375 mach_port_t server, 1376 caddr_t name, 1377 mach_msg_type_number_t nameCnt, 1378 fileport_t fileport, 1379 int ntoken, 1380 int *client_id, 1381 int *status, 1382 audit_token_t audit 1383) 1384{ 1385 kern_return_t kstatus; 1386 client_t *c; 1387 pid_t pid = (pid_t)-1; 1388 int token = generate_token(audit); 1389 1390 *client_id = token; 1391 *status = NOTIFY_STATUS_OK; 1392 1393 kstatus = __notify_server_register_file_descriptor_2(server, name, nameCnt, token, fileport, audit); 1394 if (kstatus == KERN_SUCCESS) 1395 { 1396 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1397 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1398 if (c == NULL) *status = NOTIFY_STATUS_FAILED; 1399 else c->send_val = ntoken; 1400 } 1401 1402 return kstatus; 1403} 1404 1405kern_return_t __notify_server_register_mach_port 1406( 1407 mach_port_t server, 1408 caddr_t name, 1409 mach_msg_type_number_t nameCnt, 1410 mach_port_t port, 1411 int ntoken, 1412 int *client_id, 1413 int *status, 1414 audit_token_t audit 1415) 1416{ 1417 kern_return_t kstatus; 1418 client_t *c; 1419 pid_t pid = (pid_t)-1; 1420 int token; 1421 1422 if (port == MACH_PORT_DEAD) 1423 { 1424 *status = NOTIFY_STATUS_INVALID_REQUEST; 1425 return KERN_SUCCESS; 1426 } 1427 1428 token = generate_token(audit); 1429 1430 *client_id = token; 1431 *status = NOTIFY_STATUS_OK; 1432 1433 kstatus = __notify_server_register_mach_port_2(server, name, nameCnt, token, port, audit); 1434 if (kstatus == KERN_SUCCESS) 1435 { 1436 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1437 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1438 if (c == NULL) *status = NOTIFY_STATUS_FAILED; 1439 else c->send_val = ntoken; 1440 } 1441 1442 return kstatus; 1443} 1444 1445kern_return_t __notify_server_simple_post 1446( 1447 mach_port_t server, 1448 caddr_t name, 1449 mach_msg_type_number_t nameCnt, 1450 audit_token_t audit 1451) 1452{ 1453 return __notify_server_post_4(server, name, nameCnt, audit); 1454} 1455 1456kern_return_t __notify_server_regenerate 1457( 1458 mach_port_t server, 1459 caddr_t name, 1460 mach_msg_type_number_t nameCnt, 1461 int token, 1462 uint32_t reg_type, 1463 mach_port_t port, 1464 int sig, 1465 int prev_slot, 1466 uint64_t prev_state, 1467 uint64_t prev_time, 1468 caddr_t path, 1469 mach_msg_type_number_t pathCnt, 1470 int path_flags, 1471 int *new_slot, 1472 uint64_t *new_nid, 1473 int *status, 1474 audit_token_t audit 1475) 1476{ 1477 kern_return_t kstatus; 1478 pid_t pid = (pid_t)-1; 1479 int size; 1480 name_info_t *n; 1481 client_t *c; 1482 uint64_t cid; 1483 1484 if (name == NULL) 1485 { 1486 if (path != NULL) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1487 *status = NOTIFY_STATUS_INVALID_NAME; 1488 return KERN_SUCCESS; 1489 } 1490 1491 if (name[nameCnt] != '\0') 1492 { 1493 if (path != NULL) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1494 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1495 *status = NOTIFY_STATUS_INVALID_NAME; 1496 return KERN_SUCCESS; 1497 } 1498 1499 if ((path != NULL) && (path[pathCnt] != '\0')) 1500 { 1501 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1502 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1503 *status = NOTIFY_STATUS_INVALID_REQUEST; 1504 return KERN_SUCCESS; 1505 } 1506 1507 call_statistics.regenerate++; 1508 1509 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1510 1511 log_message(ASL_LEVEL_DEBUG, "__notify_server_regenerate %s %d %d %d %u %d %d %llu %s %d\n", name, pid, token, reg_type, port, sig, prev_slot, prev_state, path, path_flags); 1512 1513 cid = make_client_id(pid, token); 1514 c = (client_t *)_nc_table_find_64(global.notify_state->client_table, cid); 1515 if (c != NULL) 1516 { 1517 /* duplicate client - this should never happen */ 1518 *status = NOTIFY_STATUS_FAILED; 1519 return KERN_SUCCESS; 1520 } 1521 1522 switch (reg_type) 1523 { 1524 case NOTIFY_TYPE_MEMORY: 1525 { 1526 /* prev_slot must be between 0 and global.nslots */ 1527 if ((prev_slot < 0) || (prev_slot >= global.nslots)) 1528 { 1529 *status = NOTIFY_STATUS_INVALID_REQUEST; 1530 return KERN_SUCCESS; 1531 } 1532 1533 kstatus = __notify_server_register_check_2(server, name, nameCnt, token, &size, new_slot, new_nid, status, audit); 1534 if (*status == NOTIFY_STATUS_OK) 1535 { 1536 if ((*new_slot != UINT32_MAX) && (global.last_shm_base != NULL)) 1537 { 1538 global.shared_memory_base[*new_slot] = global.shared_memory_base[*new_slot] + global.last_shm_base[prev_slot] - 1; 1539 global.last_shm_base[prev_slot] = 0; 1540 } 1541 } 1542 break; 1543 } 1544 case NOTIFY_TYPE_PLAIN: 1545 { 1546 kstatus = __notify_server_register_plain_2(server, name, nameCnt, token, audit); 1547 break; 1548 } 1549 case NOTIFY_TYPE_PORT: 1550 { 1551 kstatus = __notify_server_register_mach_port_2(server, name, nameCnt, token, port, audit); 1552 break; 1553 } 1554 case NOTIFY_TYPE_SIGNAL: 1555 { 1556 kstatus = __notify_server_register_signal_2(server, name, nameCnt, token, sig, audit); 1557 break; 1558 } 1559 default: break; 1560 } 1561 1562 if (path != NULL) 1563 { 1564 __notify_server_monitor_file_2(server, token, path, pathCnt, path_flags, audit); 1565 } 1566 1567 c = (client_t *)_nc_table_find_64(global.notify_state->client_table, cid); 1568 if (c == NULL) 1569 { 1570 *status = NOTIFY_STATUS_FAILED; 1571 } 1572 else 1573 { 1574 *status = NOTIFY_STATUS_OK; 1575 n = c->name_info; 1576 *new_nid = n->name_id; 1577 if (prev_time > n->state_time) n->state = prev_state; 1578 } 1579 1580 return KERN_SUCCESS; 1581} 1582