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 *name_id = 0; 348 349 *status = server_preflight(name, nameCnt, audit, -1, &uid, &gid, NULL, NULL); 350 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 351 352 call_statistics.post++; 353 call_statistics.post_by_name_and_fetch_id++; 354 355 *status = _notify_lib_check_controlled_access(global.notify_state, name, uid, gid, NOTIFY_ACCESS_WRITE); 356 if (*status != NOTIFY_STATUS_OK) 357 { 358 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 359 return KERN_SUCCESS; 360 } 361 362 n = NULL; 363 *status = daemon_post(name, uid, gid); 364 if (*status == NOTIFY_STATUS_OK) 365 { 366 n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 367 } 368 369 if (n == NULL) 370 { 371 *status = NOTIFY_STATUS_INVALID_NAME; 372 *name_id = UINT64_MAX; 373 call_statistics.post_no_op++; 374 } 375 else 376 { 377 *name_id = n->name_id; 378 } 379 380 if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s\n", name); 381 else log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s [%llu]\n", name, *name_id); 382 383 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 384 385 return KERN_SUCCESS; 386} 387 388kern_return_t __notify_server_post_4 389( 390 mach_port_t server, 391 caddr_t name, 392 mach_msg_type_number_t nameCnt, 393 audit_token_t audit 394) 395{ 396 uint64_t ignored_name_id; 397 int ignored_status; 398 kern_return_t kstatus; 399 400 kstatus = __notify_server_post_2(server, name, nameCnt, &ignored_name_id, &ignored_status, audit); 401 402 call_statistics.post_by_name_and_fetch_id--; 403 call_statistics.post_by_name++; 404 405 return kstatus; 406} 407 408kern_return_t __notify_server_post 409( 410 mach_port_t server, 411 caddr_t name, 412 mach_msg_type_number_t nameCnt, 413 int *status, 414 audit_token_t audit 415) 416{ 417 uint64_t ignored_name_id; 418 kern_return_t kstatus; 419 420 *status = NOTIFY_STATUS_OK; 421 422 kstatus = __notify_server_post_2(server, name, nameCnt, &ignored_name_id, status, audit); 423 424 call_statistics.post_by_name_and_fetch_id--; 425 call_statistics.post_by_name++; 426 427 if (*status == NOTIFY_STATUS_INVALID_NAME) *status = NOTIFY_STATUS_OK; 428 429 return kstatus; 430} 431 432kern_return_t __notify_server_register_plain_2 433( 434 mach_port_t server, 435 caddr_t name, 436 mach_msg_type_number_t nameCnt, 437 int token, 438 audit_token_t audit 439) 440{ 441 client_t *c; 442 uint64_t nid, cid; 443 uint32_t status; 444 uid_t uid = (uid_t)-1; 445 gid_t gid = (gid_t)-1; 446 pid_t pid = (pid_t)-1; 447 448 call_statistics.reg++; 449 call_statistics.reg_plain++; 450 451 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 452 if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 453 454 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_plain %s %d %d\n", name, pid, token); 455 456 status = _notify_lib_register_plain(global.notify_state, name, pid, token, -1, uid, gid, &nid); 457 if (status != NOTIFY_STATUS_OK) 458 { 459 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 460 return KERN_SUCCESS; 461 } 462 463 c = _nc_table_find_64(global.notify_state->client_table, cid); 464 465 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 466 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 467 468 register_pid(pid); 469 470 return KERN_SUCCESS; 471} 472 473kern_return_t __notify_server_register_check_2 474( 475 mach_port_t server, 476 caddr_t name, 477 mach_msg_type_number_t nameCnt, 478 int token, 479 int *size, 480 int *slot, 481 uint64_t *name_id, 482 int *status, 483 audit_token_t audit 484) 485{ 486 name_info_t *n; 487 uint32_t i, j, x, new_slot; 488 uint64_t cid; 489 client_t *c; 490 uid_t uid = (uid_t)-1; 491 gid_t gid = (gid_t)-1; 492 pid_t pid = (pid_t)-1; 493 494 *size = 0; 495 *slot = 0; 496 *name_id = 0; 497 *status = NOTIFY_STATUS_OK; 498 499 *status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 500 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 501 502 call_statistics.reg++; 503 call_statistics.reg_check++; 504 505 if (global.nslots == 0) 506 { 507 *size = -1; 508 *slot = -1; 509 return __notify_server_register_plain_2(server, name, nameCnt, token, audit); 510 } 511 512 x = (uint32_t)-1; 513 514 n = (name_info_t *)_nc_table_find(global.notify_state->name_table, name); 515 if (n != NULL) x = n->slot; 516 517 new_slot = 0; 518 if (x == (uint32_t)-1) 519 { 520 /* find a slot */ 521 new_slot = 1; 522 523 /* 524 * Check slots beginning at the current slot_id + 1, since it's likely that the 525 * next slot will be available. Keep looking until we have examined all the 526 * slots (skipping slot 0, which is reserved for notifyd). Stop if we find 527 * an unused (refcount == 0) slot. 528 */ 529 for (i = 1, j = global.slot_id + 1; i < global.nslots; i++, j++) 530 { 531 if (j >= global.nslots) j = 1; 532 if (global.shared_memory_refcount[j] == 0) 533 { 534 x = j; 535 break; 536 } 537 } 538 539 if (x == (uint32_t)-1) 540 { 541 /* 542 * We did not find an unused slot. At this point, the shared 543 * memory table is full, so we start re-using slots, beginning at 544 * global.slot_id + 1. 545 */ 546 global.slot_id++; 547 548 /* wrap around to slot 1 (slot 0 is reserved for notifyd) */ 549 if (global.slot_id >= global.nslots) global.slot_id = 1; 550 log_message(ASL_LEVEL_DEBUG, "reused shared memory slot %u\n", global.slot_id); 551 x = global.slot_id; 552 } 553 else 554 { 555 /* found a free slot */ 556 global.slot_id = x; 557 } 558 } 559 560 if (new_slot == 1) global.shared_memory_base[x] = 1; 561 global.shared_memory_refcount[x]++; 562 563 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_check %s %d %d\n", name, pid, token); 564 565 *size = global.nslots * sizeof(uint32_t); 566 *slot = x; 567 *status = _notify_lib_register_plain(global.notify_state, name, pid, token, x, uid, gid, name_id); 568 if (*status != NOTIFY_STATUS_OK) 569 { 570 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 571 return KERN_SUCCESS; 572 } 573 574 c = _nc_table_find_64(global.notify_state->client_table, cid); 575 576 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 577 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 578 579 register_pid(pid); 580 581 return KERN_SUCCESS; 582} 583 584kern_return_t __notify_server_register_signal_2 585( 586 mach_port_t server, 587 caddr_t name, 588 mach_msg_type_number_t nameCnt, 589 int token, 590 int sig, 591 audit_token_t audit 592) 593{ 594 client_t *c; 595 uint64_t name_id, cid; 596 uint32_t status; 597 uid_t uid = (uid_t)-1; 598 gid_t gid = (gid_t)-1; 599 pid_t pid = (pid_t)-1; 600 601 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 602 if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 603 604 call_statistics.reg++; 605 call_statistics.reg_signal++; 606 607 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_signal %s %d %d %d\n", name, pid, token, sig); 608 609 status = _notify_lib_register_signal(global.notify_state, name, pid, token, sig, uid, gid, &name_id); 610 if (status != NOTIFY_STATUS_OK) 611 { 612 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 613 return KERN_SUCCESS; 614 } 615 616 c = _nc_table_find_64(global.notify_state->client_table, cid); 617 618 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 619 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 620 621 register_pid(pid); 622 623 return KERN_SUCCESS; 624} 625 626kern_return_t __notify_server_register_file_descriptor_2 627( 628 mach_port_t server, 629 caddr_t name, 630 mach_msg_type_number_t nameCnt, 631 int token, 632 fileport_t fileport, 633 audit_token_t audit 634) 635{ 636 client_t *c; 637 int fd, flags; 638 uint32_t status; 639 uint64_t name_id, cid; 640 uid_t uid = (uid_t)-1; 641 gid_t gid = (gid_t)-1; 642 pid_t pid = (pid_t)-1; 643 644 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 645 if (status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 646 647 call_statistics.reg++; 648 call_statistics.reg_file++; 649 650 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_file_descriptor %s %d %d\n", name, pid, token); 651 652 fd = fileport_makefd(fileport); 653 mach_port_deallocate(mach_task_self(), fileport); 654 if (fd < 0) 655 { 656 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 657 return KERN_SUCCESS; 658 } 659 660 flags = fcntl(fd, F_GETFL, 0); 661 if (flags < 0) 662 { 663 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 664 return KERN_SUCCESS; 665 } 666 667 flags |= O_NONBLOCK; 668 if (fcntl(fd, F_SETFL, flags) < 0) 669 { 670 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 671 return KERN_SUCCESS; 672 } 673 674 status = _notify_lib_register_file_descriptor(global.notify_state, name, pid, token, fd, uid, gid, &name_id); 675 if (status != NOTIFY_STATUS_OK) 676 { 677 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 678 return KERN_SUCCESS; 679 } 680 681 c = _nc_table_find_64(global.notify_state->client_table, cid); 682 683 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 684 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 685 686 register_pid(pid); 687 688 return KERN_SUCCESS; 689} 690 691kern_return_t __notify_server_register_mach_port_2 692( 693 mach_port_t server, 694 caddr_t name, 695 mach_msg_type_number_t nameCnt, 696 int token, 697 mach_port_t port, 698 audit_token_t audit 699) 700{ 701 client_t *c; 702 uint64_t name_id, cid; 703 uint32_t status; 704 uid_t uid = (uid_t)-1; 705 gid_t gid = (gid_t)-1; 706 pid_t pid = (pid_t)-1; 707 708 if (port == MACH_PORT_DEAD) return KERN_SUCCESS; 709 710 status = server_preflight(name, nameCnt, audit, token, &uid, &gid, &pid, &cid); 711 if (status != NOTIFY_STATUS_OK) 712 { 713 mach_port_deallocate(mach_task_self(), port); 714 return KERN_SUCCESS; 715 } 716 717 call_statistics.reg++; 718 call_statistics.reg_port++; 719 720 log_message(ASL_LEVEL_DEBUG, "__notify_server_register_mach_port %s %d %d\n", name, pid, token); 721 722 status = _notify_lib_register_mach_port(global.notify_state, name, pid, token, port, uid, gid, &name_id); 723 if (status != NOTIFY_STATUS_OK) 724 { 725 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 726 mach_port_deallocate(mach_task_self(), port); 727 return KERN_SUCCESS; 728 } 729 730 c = _nc_table_find_64(global.notify_state->client_table,cid); 731 732 if (!strncmp(name, SERVICE_PREFIX, SERVICE_PREFIX_LEN)) service_open(name, c, uid, gid); 733 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 734 735 register_pid(pid); 736 register_port(c); 737 738 return KERN_SUCCESS; 739} 740 741kern_return_t __notify_server_cancel 742( 743 mach_port_t server, 744 int token, 745 int *status, 746 audit_token_t audit 747) 748{ 749 client_t *c; 750 uid_t uid = (uid_t)-1; 751 pid_t pid = (pid_t)-1; 752 753 *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, &pid, NULL); 754 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 755 756 call_statistics.cancel++; 757 758 log_message(ASL_LEVEL_DEBUG, "__notify_server_cancel %d %d\n", pid, token); 759 760 *status = NOTIFY_STATUS_OK; 761 762 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 763 if (c == NULL) *status = NOTIFY_STATUS_FAILED; 764 else cancel_subscription(c); 765 766 return KERN_SUCCESS; 767} 768 769kern_return_t __notify_server_cancel_2 770( 771 mach_port_t server, 772 int token, 773 audit_token_t audit 774) 775{ 776 int ignored; 777 return __notify_server_cancel(server, token, &ignored, audit); 778} 779 780kern_return_t __notify_server_suspend 781( 782 mach_port_t server, 783 int token, 784 int *status, 785 audit_token_t audit 786) 787{ 788 pid_t pid = (pid_t)-1; 789 790 *status = server_preflight(NULL, 0, audit, -1, NULL, NULL, &pid, NULL); 791 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 792 793 call_statistics.suspend++; 794 795 log_message(ASL_LEVEL_DEBUG, "__notify_server_suspend %d %d\n", pid, token); 796 797 _notify_lib_suspend(global.notify_state, pid, token); 798 *status = NOTIFY_STATUS_OK; 799 800 return KERN_SUCCESS; 801} 802 803kern_return_t __notify_server_resume 804( 805 mach_port_t server, 806 int token, 807 int *status, 808 audit_token_t audit 809) 810{ 811 pid_t pid = (pid_t)-1; 812 813 *status = server_preflight(NULL, 0, audit, -1, NULL, NULL, &pid, NULL); 814 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 815 816 call_statistics.resume++; 817 818 log_message(ASL_LEVEL_DEBUG, "__notify_server_resume %d %d\n", pid, token); 819 820 _notify_lib_resume(global.notify_state, pid, token); 821 *status = NOTIFY_STATUS_OK; 822 823 return KERN_SUCCESS; 824} 825 826static uid_t 827uid_for_pid(pid_t pid) 828{ 829 int mib[4]; 830 struct kinfo_proc info; 831 size_t size = sizeof(struct kinfo_proc); 832 833 mib[0] = CTL_KERN; 834 mib[1] = KERN_PROC; 835 mib[2] = KERN_PROC_PID; 836 mib[3] = pid; 837 838 sysctl(mib, 4, &info, &size, 0, 0); 839 840 return (uid_t)info.kp_eproc.e_ucred.cr_uid; 841} 842 843kern_return_t __notify_server_suspend_pid 844( 845 mach_port_t server, 846 int pid, 847 int *status, 848 audit_token_t audit 849) 850{ 851 uid_t uid, target_uid; 852 853 uid = (uid_t)-1; 854 855 *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, NULL, NULL); 856 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 857 858 call_statistics.suspend_pid++; 859 860 log_message(ASL_LEVEL_DEBUG, "__notify_server_suspend_pid %d\n", pid); 861 862 target_uid = uid_for_pid(pid); 863 864 if ((uid != 0) && (target_uid != uid)) 865 { 866 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 867 return KERN_SUCCESS; 868 } 869 870 *status = NOTIFY_STATUS_OK; 871 872 _notify_lib_suspend_proc(global.notify_state, pid); 873 874 return KERN_SUCCESS; 875} 876 877kern_return_t __notify_server_resume_pid 878( 879 mach_port_t server, 880 int pid, 881 int *status, 882 audit_token_t audit 883) 884{ 885 uid_t uid, target_uid; 886 887 uid = (uid_t)-1; 888 889 *status = server_preflight(NULL, 0, audit, -1, &uid, NULL, NULL, NULL); 890 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 891 892 call_statistics.resume_pid++; 893 894 log_message(ASL_LEVEL_DEBUG, "__notify_server_resume_pid %d\n", pid); 895 896 target_uid = uid_for_pid(pid); 897 898 if ((uid != 0) && (target_uid != uid)) 899 { 900 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 901 return KERN_SUCCESS; 902 } 903 904 *status = NOTIFY_STATUS_OK; 905 906 _notify_lib_resume_proc(global.notify_state, pid); 907 908 return KERN_SUCCESS; 909} 910 911kern_return_t __notify_server_check 912( 913 mach_port_t server, 914 int token, 915 int *check, 916 int *status, 917 audit_token_t audit 918) 919{ 920 pid_t pid = (gid_t)-1; 921 922 *check = 0; 923 924 call_statistics.check++; 925 926 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 927 928 log_message(ASL_LEVEL_DEBUG, "__notify_server_check %d %d\n", pid, token); 929 930 *status = _notify_lib_check(global.notify_state, pid, token, check); 931 return KERN_SUCCESS; 932} 933 934kern_return_t __notify_server_get_state 935( 936 mach_port_t server, 937 int token, 938 uint64_t *state, 939 int *status, 940 audit_token_t audit 941) 942{ 943 uid_t uid = (uid_t)-1; 944 gid_t gid = (gid_t)-1; 945 pid_t pid = (pid_t)-1; 946 client_t *c; 947 948 *state = 0; 949 950 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 951 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 952 953 call_statistics.get_state++; 954 call_statistics.get_state_by_client++; 955 956 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state %d %d\n", pid, token); 957 958 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 959 if ((c == NULL) || (c->name_info == NULL)) 960 { 961 *status = NOTIFY_STATUS_FAILED; 962 } 963 else 964 { 965 *status = _notify_lib_get_state(global.notify_state, c->name_info->name_id, state, uid, gid); 966 } 967 968 return KERN_SUCCESS; 969} 970 971kern_return_t __notify_server_get_state_2 972( 973 mach_port_t server, 974 uint64_t name_id, 975 uint64_t *state, 976 int *status, 977 audit_token_t audit 978) 979{ 980 uid_t uid = (uid_t)-1; 981 gid_t gid = (gid_t)-1; 982 983 *state = 0; 984 985 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, NULL, NULL); 986 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 987 988 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_2 %llu\n", name_id); 989 990 *status = _notify_lib_get_state(global.notify_state, name_id, state, uid, gid); 991 return KERN_SUCCESS; 992} 993 994kern_return_t __notify_server_get_state_3 995( 996 mach_port_t server, 997 int token, 998 uint64_t *state, 999 uint64_t *name_id, 1000 int *status, 1001 audit_token_t audit 1002) 1003{ 1004 uid_t uid = (uid_t)-1; 1005 gid_t gid = (gid_t)-1; 1006 pid_t pid = (pid_t)-1; 1007 client_t *c; 1008 1009 *state = 0; 1010 *name_id = 0; 1011 1012 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 1013 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1014 1015 call_statistics.get_state++; 1016 call_statistics.get_state_by_client_and_fetch_id++; 1017 1018 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1019 if ((c == NULL) || (c->name_info == NULL)) 1020 { 1021 *status = NOTIFY_STATUS_FAILED; 1022 *name_id = UINT64_MAX; 1023 } 1024 else 1025 { 1026 *status = _notify_lib_get_state(global.notify_state, c->name_info->name_id, state, uid, gid); 1027 *name_id = c->name_info->name_id; 1028 } 1029 1030 if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_3 %d %d\n", pid, token); 1031 else log_message(ASL_LEVEL_DEBUG, "__notify_server_get_state_3 %d %d [%llu]\n", pid, token, *name_id); 1032 1033 return KERN_SUCCESS; 1034} 1035 1036kern_return_t __notify_server_set_state_3 1037( 1038 mach_port_t server, 1039 int token, 1040 uint64_t state, 1041 uint64_t *name_id, 1042 int *status, 1043 audit_token_t audit 1044) 1045{ 1046 client_t *c; 1047 uid_t uid = (uid_t)-1; 1048 gid_t gid = (gid_t)-1; 1049 pid_t pid = (pid_t)-1; 1050 1051 *name_id = 0; 1052 1053 *status = server_preflight(NULL, 0, audit, -1, &uid, &gid, &pid, NULL); 1054 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1055 1056 call_statistics.set_state++; 1057 call_statistics.set_state_by_client_and_fetch_id++; 1058 1059 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1060 if ((c == NULL) || (c->name_info == NULL)) 1061 { 1062 *status = NOTIFY_STATUS_FAILED; 1063 *name_id = UINT64_MAX; 1064 } 1065 else 1066 { 1067 *status = _notify_lib_set_state(global.notify_state, c->name_info->name_id, state, uid, gid); 1068 *name_id = c->name_info->name_id; 1069 } 1070 1071 if (*name_id == UINT64_MAX) log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_3 %d %d %llu\n", pid, token, state); 1072 else log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_3 %d %d %llu [%llu]\n", pid, token, state, *name_id); 1073 1074 return KERN_SUCCESS; 1075} 1076 1077kern_return_t __notify_server_set_state 1078( 1079 mach_port_t server, 1080 int token, 1081 uint64_t state, 1082 int *status, 1083 audit_token_t audit 1084) 1085{ 1086 uint64_t ignored; 1087 kern_return_t kstatus; 1088 1089 *status = NOTIFY_STATUS_OK; 1090 1091 kstatus = __notify_server_set_state_3(server, token, state, &ignored, status, audit); 1092 1093 call_statistics.set_state_by_client_and_fetch_id--; 1094 call_statistics.set_state_by_client++; 1095 1096 return kstatus; 1097} 1098 1099kern_return_t __notify_server_set_state_2 1100( 1101 mach_port_t server, 1102 uint64_t name_id, 1103 uint64_t state, 1104 audit_token_t audit 1105) 1106{ 1107 uint32_t status; 1108 uid_t uid = (uid_t)-1; 1109 gid_t gid = (gid_t)-1; 1110 1111 if (global.notify_state == NULL) return KERN_SUCCESS; 1112 1113 call_statistics.set_state++; 1114 call_statistics.set_state_by_id++; 1115 1116 audit_token_to_au32(audit, NULL, &uid, &gid, NULL, NULL, NULL, NULL, NULL); 1117 1118 log_message(ASL_LEVEL_DEBUG, "__notify_server_set_state_2 %llu %llu\n", name_id, state); 1119 1120 status = _notify_lib_set_state(global.notify_state, name_id, state, uid, gid); 1121 return KERN_SUCCESS; 1122} 1123 1124kern_return_t __notify_server_set_owner 1125( 1126 mach_port_t server, 1127 caddr_t name, 1128 mach_msg_type_number_t nameCnt, 1129 int uid, 1130 int gid, 1131 int *status, 1132 audit_token_t audit 1133) 1134{ 1135 uid_t auid = (uid_t)-1; 1136 1137 *status = server_preflight(name, nameCnt, audit, -1, &auid, NULL, NULL, NULL); 1138 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1139 1140 call_statistics.set_owner++; 1141 1142 log_message(ASL_LEVEL_DEBUG, "__notify_server_set_owner %s %d %d\n", name, uid, gid); 1143 1144 /* only root may set owner for names */ 1145 if (auid != 0) 1146 { 1147 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1148 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 1149 return KERN_SUCCESS; 1150 } 1151 1152 *status = _notify_lib_set_owner(global.notify_state, name, uid, gid); 1153 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1154 return KERN_SUCCESS; 1155} 1156 1157kern_return_t __notify_server_get_owner 1158( 1159 mach_port_t server, 1160 caddr_t name, 1161 mach_msg_type_number_t nameCnt, 1162 int *uid, 1163 int *gid, 1164 int *status, 1165 audit_token_t audit 1166) 1167{ 1168 *uid = 0; 1169 *gid = 0; 1170 1171 *status = server_preflight(name, nameCnt, audit, -1, NULL, NULL, NULL, NULL); 1172 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1173 1174 call_statistics.get_owner++; 1175 1176 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_owner %s\n", name); 1177 1178 *status = _notify_lib_get_owner(global.notify_state, name, (uint32_t *)uid, (uint32_t *)gid); 1179 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1180 return KERN_SUCCESS; 1181} 1182 1183kern_return_t __notify_server_set_access 1184( 1185 mach_port_t server, 1186 caddr_t name, 1187 mach_msg_type_number_t nameCnt, 1188 int mode, 1189 int *status, 1190 audit_token_t audit 1191) 1192{ 1193 uint32_t u, g; 1194 uid_t uid = (uid_t)-1; 1195 gid_t gid = (gid_t)-1; 1196 1197 *status = server_preflight(name, nameCnt, audit, -1, &uid, &gid, NULL, NULL); 1198 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1199 1200 call_statistics.set_access++; 1201 1202 log_message(ASL_LEVEL_DEBUG, "__notify_server_set_access %s 0x%03x\n", name, mode); 1203 1204 _notify_lib_get_owner(global.notify_state, name, &u, &g); 1205 1206 /* only root and owner may set access for names */ 1207 if ((uid != 0) && (uid != u)) 1208 { 1209 *status = NOTIFY_STATUS_NOT_AUTHORIZED; 1210 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1211 return KERN_SUCCESS; 1212 } 1213 1214 *status = _notify_lib_set_access(global.notify_state, name, mode); 1215 if ((u != 0) || (g != 0)) *status = _notify_lib_set_owner(global.notify_state, name, u, g); 1216 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1217 return KERN_SUCCESS; 1218} 1219 1220kern_return_t __notify_server_get_access 1221( 1222 mach_port_t server, 1223 caddr_t name, 1224 mach_msg_type_number_t nameCnt, 1225 int *mode, 1226 int *status, 1227 audit_token_t audit 1228) 1229{ 1230 *mode = 0; 1231 1232 *status = server_preflight(name, nameCnt, audit, -1, NULL, NULL, NULL, NULL); 1233 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1234 1235 call_statistics.get_access++; 1236 1237 log_message(ASL_LEVEL_DEBUG, "__notify_server_get_access %s\n", name); 1238 1239 *status = _notify_lib_get_access(global.notify_state, name, (uint32_t *)mode); 1240 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1241 return KERN_SUCCESS; 1242} 1243 1244/* Unsupported because it makes no sense */ 1245kern_return_t __notify_server_release_name 1246( 1247 mach_port_t server, 1248 caddr_t name, 1249 mach_msg_type_number_t nameCnt, 1250 int *status, 1251 audit_token_t audit 1252) 1253{ 1254 *status = NOTIFY_STATUS_FAILED; 1255 return KERN_SUCCESS; 1256} 1257 1258kern_return_t __notify_server_monitor_file 1259( 1260 mach_port_t server, 1261 int token, 1262 caddr_t path, 1263 mach_msg_type_number_t pathCnt, 1264 int flags, 1265 int *status, 1266 audit_token_t audit 1267) 1268{ 1269 client_t *c; 1270 name_info_t *n; 1271 uid_t uid = (uid_t)-1; 1272 gid_t gid = (gid_t)-1; 1273 pid_t pid = (pid_t)-1; 1274 uint32_t ubits = (uint32_t)flags; 1275 1276 *status = server_preflight(path, pathCnt, audit, -1, &uid, &gid, &pid, NULL); 1277 if (*status != NOTIFY_STATUS_OK) return KERN_SUCCESS; 1278 1279 call_statistics.monitor_file++; 1280 1281 log_message(ASL_LEVEL_DEBUG, "__notify_server_monitor_file %d %d %s 0x%08x\n", pid, token, path, ubits); 1282 1283 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1284 if (c == NULL) 1285 { 1286 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1287 *status = NOTIFY_STATUS_INVALID_REQUEST; 1288 return KERN_SUCCESS; 1289 } 1290 1291 n = c->name_info; 1292 if (n == NULL) 1293 { 1294 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1295 *status = NOTIFY_STATUS_INVALID_REQUEST; 1296 return KERN_SUCCESS; 1297 } 1298 1299 *status = service_open_path_private(n->name, c, path, uid, gid, ubits); 1300 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1301 1302 return KERN_SUCCESS; 1303} 1304 1305kern_return_t __notify_server_monitor_file_2 1306( 1307 mach_port_t server, 1308 int token, 1309 caddr_t path, 1310 mach_msg_type_number_t pathCnt, 1311 int flags, 1312 audit_token_t audit 1313) 1314{ 1315 int ignored; 1316 return __notify_server_monitor_file(server, token, path, pathCnt, flags, &ignored, audit); 1317} 1318 1319/* 1320 * Original routines provide compatibility for legacy clients. 1321 * iOS simulator uses them. 1322 */ 1323 1324/* 1325 * Generates a integer "token" for legacy client registrations. 1326 */ 1327static int 1328generate_token(audit_token_t audit) 1329{ 1330 static int legacy_id = 0; 1331 1332 if (++legacy_id == -1) legacy_id = 1; 1333 return legacy_id; 1334} 1335 1336kern_return_t __notify_server_register_plain 1337( 1338 mach_port_t server, 1339 caddr_t name, 1340 mach_msg_type_number_t nameCnt, 1341 int *client_id, 1342 int *status, 1343 audit_token_t audit 1344) 1345{ 1346 int token = generate_token(audit); 1347 1348 *client_id = token; 1349 *status = NOTIFY_STATUS_OK; 1350 1351 return __notify_server_register_plain_2(server, name, nameCnt, token, audit); 1352} 1353 1354kern_return_t __notify_server_register_check 1355( 1356 mach_port_t server, 1357 caddr_t name, 1358 mach_msg_type_number_t nameCnt, 1359 int *size, 1360 int *slot, 1361 int *client_id, 1362 int *status, 1363 audit_token_t audit 1364) 1365{ 1366 *size = 0; 1367 *slot = 0; 1368 *status = NOTIFY_STATUS_OK; 1369 1370 uint64_t nid; 1371 int token = generate_token(audit); 1372 1373 *client_id = token; 1374 1375 return __notify_server_register_check_2(server, name, nameCnt, token, size, slot, &nid, status, audit); 1376} 1377 1378kern_return_t __notify_server_register_signal 1379( 1380 mach_port_t server, 1381 caddr_t name, 1382 mach_msg_type_number_t nameCnt, 1383 int sig, 1384 int *client_id, 1385 int *status, 1386 audit_token_t audit 1387) 1388{ 1389 int token = generate_token(audit); 1390 1391 *client_id = token; 1392 *status = NOTIFY_STATUS_OK; 1393 1394 return __notify_server_register_signal_2(server, name, nameCnt, token, sig, audit); 1395} 1396 1397kern_return_t __notify_server_register_file_descriptor 1398( 1399 mach_port_t server, 1400 caddr_t name, 1401 mach_msg_type_number_t nameCnt, 1402 fileport_t fileport, 1403 int ntoken, 1404 int *client_id, 1405 int *status, 1406 audit_token_t audit 1407) 1408{ 1409 kern_return_t kstatus; 1410 client_t *c; 1411 pid_t pid = (pid_t)-1; 1412 int token = generate_token(audit); 1413 1414 *client_id = token; 1415 *status = NOTIFY_STATUS_OK; 1416 1417 kstatus = __notify_server_register_file_descriptor_2(server, name, nameCnt, token, fileport, audit); 1418 if (kstatus == KERN_SUCCESS) 1419 { 1420 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1421 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1422 if (c == NULL) *status = NOTIFY_STATUS_FAILED; 1423 else c->send_val = ntoken; 1424 } 1425 1426 return kstatus; 1427} 1428 1429kern_return_t __notify_server_register_mach_port 1430( 1431 mach_port_t server, 1432 caddr_t name, 1433 mach_msg_type_number_t nameCnt, 1434 mach_port_t port, 1435 int ntoken, 1436 int *client_id, 1437 int *status, 1438 audit_token_t audit 1439) 1440{ 1441 kern_return_t kstatus; 1442 client_t *c; 1443 pid_t pid = (pid_t)-1; 1444 int token; 1445 1446 *client_id = 0; 1447 *status = NOTIFY_STATUS_OK; 1448 1449 if (port == MACH_PORT_DEAD) 1450 { 1451 if ((name != NULL) && (nameCnt > 0)) vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1452 *status = NOTIFY_STATUS_INVALID_REQUEST; 1453 return KERN_SUCCESS; 1454 } 1455 1456 token = generate_token(audit); 1457 1458 *client_id = token; 1459 *status = NOTIFY_STATUS_OK; 1460 1461 kstatus = __notify_server_register_mach_port_2(server, name, nameCnt, token, port, audit); 1462 if (kstatus == KERN_SUCCESS) 1463 { 1464 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1465 c = _nc_table_find_64(global.notify_state->client_table, make_client_id(pid, token)); 1466 if (c == NULL) *status = NOTIFY_STATUS_FAILED; 1467 else c->send_val = ntoken; 1468 } 1469 1470 return kstatus; 1471} 1472 1473kern_return_t __notify_server_simple_post 1474( 1475 mach_port_t server, 1476 caddr_t name, 1477 mach_msg_type_number_t nameCnt, 1478 audit_token_t audit 1479) 1480{ 1481 return __notify_server_post_4(server, name, nameCnt, audit); 1482} 1483 1484kern_return_t __notify_server_regenerate 1485( 1486 mach_port_t server, 1487 caddr_t name, 1488 mach_msg_type_number_t nameCnt, 1489 int token, 1490 uint32_t reg_type, 1491 mach_port_t port, 1492 int sig, 1493 int prev_slot, 1494 uint64_t prev_state, 1495 uint64_t prev_time, 1496 caddr_t path, 1497 mach_msg_type_number_t pathCnt, 1498 int path_flags, 1499 int *new_slot, 1500 uint64_t *new_nid, 1501 int *status, 1502 audit_token_t audit 1503) 1504{ 1505 kern_return_t kstatus; 1506 pid_t pid = (pid_t)-1; 1507 int size; 1508 name_info_t *n; 1509 client_t *c; 1510 uint64_t cid; 1511 1512 *new_slot = 0; 1513 *new_nid = 0; 1514 *status = NOTIFY_STATUS_OK; 1515 1516 if (name == NULL) 1517 { 1518 if (path != NULL) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1519 *status = NOTIFY_STATUS_INVALID_NAME; 1520 return KERN_SUCCESS; 1521 } 1522 1523 if (name[nameCnt] != '\0') 1524 { 1525 if (path != NULL) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1526 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1527 *status = NOTIFY_STATUS_INVALID_NAME; 1528 return KERN_SUCCESS; 1529 } 1530 1531 if ((path != NULL) && (path[pathCnt] != '\0')) 1532 { 1533 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1534 vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1535 *status = NOTIFY_STATUS_INVALID_REQUEST; 1536 return KERN_SUCCESS; 1537 } 1538 1539 call_statistics.regenerate++; 1540 1541 audit_token_to_au32(audit, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); 1542 1543 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); 1544 1545 cid = make_client_id(pid, token); 1546 c = (client_t *)_nc_table_find_64(global.notify_state->client_table, cid); 1547 if (c != NULL) 1548 { 1549 /* duplicate client - this should never happen */ 1550 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1551 if ((path != NULL) && (pathCnt > 0)) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1552 *status = NOTIFY_STATUS_FAILED; 1553 return KERN_SUCCESS; 1554 } 1555 1556 switch (reg_type) 1557 { 1558 case NOTIFY_TYPE_MEMORY: 1559 { 1560 /* prev_slot must be between 0 and global.nslots */ 1561 if ((prev_slot < 0) || (prev_slot >= global.nslots)) 1562 { 1563 *status = NOTIFY_STATUS_INVALID_REQUEST; 1564 return KERN_SUCCESS; 1565 } 1566 1567 kstatus = __notify_server_register_check_2(server, name, nameCnt, token, &size, new_slot, new_nid, status, audit); 1568 if (*status == NOTIFY_STATUS_OK) 1569 { 1570 if ((*new_slot != UINT32_MAX) && (global.last_shm_base != NULL)) 1571 { 1572 global.shared_memory_base[*new_slot] = global.shared_memory_base[*new_slot] + global.last_shm_base[prev_slot] - 1; 1573 global.last_shm_base[prev_slot] = 0; 1574 } 1575 } 1576 break; 1577 } 1578 case NOTIFY_TYPE_PLAIN: 1579 { 1580 kstatus = __notify_server_register_plain_2(server, name, nameCnt, token, audit); 1581 break; 1582 } 1583 case NOTIFY_TYPE_PORT: 1584 { 1585 kstatus = __notify_server_register_mach_port_2(server, name, nameCnt, token, port, audit); 1586 break; 1587 } 1588 case NOTIFY_TYPE_SIGNAL: 1589 { 1590 kstatus = __notify_server_register_signal_2(server, name, nameCnt, token, sig, audit); 1591 break; 1592 } 1593 case NOTIFY_TYPE_FILE: /* fall through */ 1594 default: 1595 { 1596 /* can not regenerate this type */ 1597 vm_deallocate(mach_task_self(), (vm_address_t)name, nameCnt); 1598 if ((path != NULL) && (pathCnt > 0)) vm_deallocate(mach_task_self(), (vm_address_t)path, pathCnt); 1599 *status = NOTIFY_STATUS_FAILED; 1600 return KERN_SUCCESS; 1601 } 1602 } 1603 1604 if (path != NULL) 1605 { 1606 __notify_server_monitor_file_2(server, token, path, pathCnt, path_flags, audit); 1607 } 1608 1609 c = (client_t *)_nc_table_find_64(global.notify_state->client_table, cid); 1610 if (c == NULL) 1611 { 1612 *status = NOTIFY_STATUS_FAILED; 1613 } 1614 else 1615 { 1616 *status = NOTIFY_STATUS_OK; 1617 n = c->name_info; 1618 *new_nid = n->name_id; 1619 if (prev_time > n->state_time) n->state = prev_state; 1620 } 1621 1622 return KERN_SUCCESS; 1623} 1624