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