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