xref: /NextBSD/usr.sbin/notifyd/notify_proc.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
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