1/*
2 * Copyright (c) 2004, 2013 Apple Computer, 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
25/* -----------------------------------------------------------------------------
26includes
27----------------------------------------------------------------------------- */
28#include <sys/errno.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/param.h>
32#include <sys/fcntl.h>
33#include <sys/ucred.h>
34#include <CoreFoundation/CoreFoundation.h>
35#include <SystemConfiguration/SystemConfiguration.h>
36#include <mach/mach.h>
37#include <mach/mach_error.h>
38#include <CoreFoundation/CFMachPort.h>
39#include <SystemConfiguration/SCPrivate.h>      // for SCLog()
40#include <SystemConfiguration/VPNPrivate.h>
41#include <SystemConfiguration/VPNTunnel.h>
42#include <SystemConfiguration/SCValidation.h>
43#include <Security/SecItem.h>
44#include <Security/SecCertificatePriv.h>
45#include <Security/Security.h>
46#include <Security/SecTask.h>
47#include "bsm/libbsm.h"
48
49#include "scnc_client.h"
50#include "scnc_main.h"
51#include "scnc_utils.h"
52#include "pppcontroller.h"
53#include "pppcontroller_types.h"
54#include "pppcontrollerServer.h"
55#include "scnc_mach_server.h"
56#include "app_layer.h"
57#include "flow_divert_controller.h"
58#include "network_detection.h"
59#include "controller_options.h"
60
61/* -----------------------------------------------------------------------------
62definitions
63----------------------------------------------------------------------------- */
64
65#ifndef kSCStatusConnectionNoService
66#define kSCStatusConnectionNoService 5001
67#endif
68
69
70#define	IPCSENDTIMEOUT	120				// timeout value for sending IPC message to client
71
72/* -----------------------------------------------------------------------------
73forward declarations
74----------------------------------------------------------------------------- */
75
76void server_handle_request(CFMachPortRef port, void *msg, CFIndex size, void *info);
77
78/* -----------------------------------------------------------------------------
79globals
80----------------------------------------------------------------------------- */
81
82static CFMachPortRef		gServer_cfport;
83static CFMachPortRef		gServer_cfport_priv;
84
85static mach_port_t          gServer_machport;
86static mach_port_t          gServer_machport_priv;
87
88static Boolean hasEntitlement(audit_token_t audit_token, CFStringRef entitlement, CFStringRef vpntype);
89
90
91extern CFRunLoopRef			gControllerRunloop;
92extern CFRunLoopSourceRef	gPluginRunloop;
93extern CFRunLoopSourceRef	gTerminalrls;
94
95/*
96 * Name: com.apple.private.SCNetworkConnection-proxy-user
97 * Type of value: Boolean
98 * Function: gives the entitled process the ability to "masquerade" as another process when working
99 *           with the SCNetworkConnection SPI.
100 */
101#define kSCVPNConnectionEntitlementProxyUser CFSTR("com.apple.private.SCNetworkConnection-proxy-user")
102
103/*
104 * Name: com.apple.private.SCNetworkConnection-flow-divert
105 * Type of value: Boolean
106 * Function: gives the entitled process the ability to enable flow divert on TCP sockets.
107 */
108#define kSCVPNConnectionEntitlementFlowDivert CFSTR("com.apple.private.SCNetworkConnection-flow-divert")
109
110/* -----------------------------------------------------------------------------
111----------------------------------------------------------------------------- */
112__private_extern__
113kern_return_t
114_pppcontroller_attach_proxy(mach_port_t server,
115							xmlData_t nameRef,		/* raw XML bytes */
116							mach_msg_type_number_t nameLen,
117							mach_port_t bootstrap,
118							mach_port_t notify,
119							mach_port_t au_session,
120							int uid,
121							int gid,
122							int pid,
123							mach_port_t *session,
124							int * result,
125							audit_token_t audit_token)
126{
127	CFStringRef			serviceID = NULL;
128	CFMachPortRef		port = NULL;
129	CFRunLoopSourceRef  rls = NULL;
130	struct client		*client = NULL;
131	mach_port_t			oldport;
132	uid_t				audit_euid = -1;
133	gid_t				audit_egid = -1;
134	pid_t				audit_pid = -1;
135    Boolean             has_machport_priv = FALSE;
136
137    if ( server == gServer_machport_priv){
138        SCLog(TRUE, LOG_DEBUG, CFSTR("_pppcontroller_attach_proxy server is priv server gServer_machport_priv %p"),
139              gServer_machport_priv );
140        has_machport_priv = TRUE;
141    }
142    else
143        SCLog(TRUE, LOG_DEBUG, CFSTR("_pppcontroller_attach_proxy server is norm %p"), gServer_machport);
144
145	*session = MACH_PORT_NULL;
146
147    SCLog(TRUE, LOG_DEBUG, CFSTR("_pppcontroller_attach_proxy client uid %u, gid %u, pid %u"), uid, gid, pid);
148
149	/* un-serialize the serviceID */
150	if (!_SCUnserializeString(&serviceID, NULL, (void *)nameRef, nameLen)) {
151		*result = kSCStatusFailed;
152		goto failed;
153	}
154
155	if (!isA_CFString(serviceID)) {
156		*result = kSCStatusInvalidArgument;
157		goto failed;
158	}
159
160	/* only allow "root" callers to change the client uid/gid/pid */
161	audit_token_to_au32(audit_token,
162						NULL,			// auidp
163						&audit_euid,	// euid
164						&audit_egid,	// egid
165						NULL,			// ruid
166						NULL,			// rgid
167						&audit_pid,		// pid
168						NULL,			// asid
169						NULL);			// tid
170
171    if (((uid != audit_euid) || (gid != audit_egid) || (pid != audit_pid))) {
172        /*
173         * the caller is trying to masquerade
174         * as some other user/process.
175         */
176
177        /* does caller has the right entitlement */
178        if (!(hasEntitlement(audit_token, kSCVPNConnectionEntitlementProxyUser, NULL))){
179            SCLog(TRUE, LOG_ERR, CFSTR("_pppcontroller_attach_proxy client fails entitlement for client uid change"));
180           *result = kSCStatusAccessError;
181            goto failed;
182        }
183    }
184
185
186	//if ((findbyserviceID(serviceID)) == 0) {
187	//	*result = kSCStatusInvalidArgument;
188	//	goto failed;
189	//}
190
191	/* allocate session port */
192	(void) mach_port_allocate(mach_task_self(),
193							  MACH_PORT_RIGHT_RECEIVE,
194							  session);
195
196    /*
197     * Note: we create the CFMachPort *before* we insert a send
198     *       right present to ensure that CF does not establish
199     *       it's dead name notification.
200     */
201	port = _SC_CFMachPortCreateWithPort("PPPController/PPP", *session, server_handle_request, NULL);
202
203    /* insert send right that will be moved to the client */
204	(void) mach_port_insert_right(mach_task_self(),
205								  *session,
206								  *session,
207								  MACH_MSG_TYPE_MAKE_SEND);
208
209	/* Request a notification when/if the client dies */
210	(void) mach_port_request_notification(mach_task_self(),
211										  *session,
212										  MACH_NOTIFY_NO_SENDERS,
213										  1,
214										  *session,
215										  MACH_MSG_TYPE_MAKE_SEND_ONCE,
216										  &oldport);
217
218	/* add to runloop */
219	rls = CFMachPortCreateRunLoopSource(NULL, port, 0);
220	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
221
222	client = client_new_mach(port, rls, serviceID, uid, gid, pid, bootstrap, notify, au_session, has_machport_priv);
223	if (client == 0) {
224		*result = kSCStatusFailed;
225		goto failed;
226	}
227
228	*result = kSCStatusOK;
229
230	my_CFRelease(&serviceID);
231	my_CFRelease(&port);
232	my_CFRelease(&rls);
233    return KERN_SUCCESS;
234
235 failed:
236	my_CFRelease(&serviceID);
237	if (port) {
238		CFMachPortInvalidate(port);
239		my_CFRelease(&port);
240	}
241	if (rls) {
242		CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
243		my_CFRelease(&rls);
244	}
245	if (*session != MACH_PORT_NULL) {
246		mach_port_mod_refs(mach_task_self(), *session, MACH_PORT_RIGHT_SEND   , -1);
247		mach_port_mod_refs(mach_task_self(), *session, MACH_PORT_RIGHT_RECEIVE, -1);
248		*session = MACH_PORT_NULL;
249	}
250	if (client) {
251		client_dispose(client);
252	} else {
253		if (bootstrap != MACH_PORT_NULL)
254			mach_port_deallocate(mach_task_self(), bootstrap);
255		if (notify != MACH_PORT_NULL)
256			mach_port_deallocate(mach_task_self(), notify);
257	}
258    return KERN_SUCCESS;
259}
260
261__private_extern__
262kern_return_t
263_pppcontroller_attach(mach_port_t server,
264					  xmlData_t nameRef,		/* raw XML bytes */
265					  mach_msg_type_number_t nameLen,
266					  mach_port_t bootstrap,
267					  mach_port_t notify,
268					  mach_port_t au_session,
269					  mach_port_t *session,
270					  int * result,
271					  audit_token_t audit_token)
272{
273	kern_return_t	kr;
274	uid_t			euid	= -1;
275	gid_t			egid	= -1;
276	pid_t			pid		= -1;
277
278	audit_token_to_au32(audit_token,
279						NULL,			// auidp
280						&euid,			// euid
281						&egid,			// egid
282						NULL,			// ruid
283						NULL,			// rgid
284						&pid,			// pid
285						NULL,			// asid
286						NULL);			// tid
287
288	kr = _pppcontroller_attach_proxy(server,
289									 nameRef,
290									 nameLen,
291									 bootstrap,
292									 notify,
293									 au_session,
294									 euid,
295									 egid,
296									 pid,
297									 session,
298									 result,
299									 audit_token);
300	return kr;
301}
302
303/* -----------------------------------------------------------------------------
304----------------------------------------------------------------------------- */
305__private_extern__
306kern_return_t
307_pppcontroller_getstatus(mach_port_t session,
308	    int * status,
309		int * result)
310{
311	struct client		*client;
312	struct service		*serv = 0;
313
314    *status = kSCNetworkConnectionInvalid;
315
316    client = client_findbymachport(session);
317    if (!client ) {
318		*result = kSCStatusInvalidArgument;
319		goto failed;
320    }
321
322	if ((serv = findbyserviceID(client->serviceID)) == 0) {
323		*result = kSCStatusConnectionNoService;
324		goto failed;
325	}
326
327	*status = scnc_getstatus(serv);
328
329	*result = kSCStatusOK;
330    return (KERN_SUCCESS);
331
332failed:
333    return (KERN_SUCCESS);
334}
335
336/* -----------------------------------------------------------------------------
337----------------------------------------------------------------------------- */
338__private_extern__
339kern_return_t
340_pppcontroller_copyextendedstatus(mach_port_t session,
341		xmlDataOut_t * extstatus,
342		mach_msg_type_number_t * extstatus_len,
343		int * result)
344{
345	struct client		*client;
346	struct service		*serv = 0;
347	void				*reply = 0;
348	u_int16_t			replylen = 0;
349
350    client = client_findbymachport(session);
351    if (!client ) {
352		*result = kSCStatusInvalidArgument;
353		goto failed;
354    }
355
356	if ((serv = findbyserviceID(client->serviceID)) == 0) {
357		*result = kSCStatusConnectionNoService;
358		goto failed;
359	}
360
361	if (scnc_copyextendedstatus(serv, &reply, &replylen)) {
362		*result = kSCStatusFailed;
363		goto failed;
364	}
365
366	*extstatus = reply;
367	*extstatus_len = replylen;
368
369	*result = kSCStatusOK;
370    return (KERN_SUCCESS);
371
372failed:
373	*extstatus = 0;
374	*extstatus_len = 0;
375    return (KERN_SUCCESS);
376}
377
378
379/* -----------------------------------------------------------------------------
380----------------------------------------------------------------------------- */
381__private_extern__
382kern_return_t
383_pppcontroller_copystatistics(mach_port_t session,
384		xmlDataOut_t * statistics,
385		mach_msg_type_number_t * statistics_len,
386		int * result)
387{
388	struct client		*client;
389	struct service		*serv = 0;
390	void				*reply = 0;
391	u_int16_t			replylen = 0;
392
393    client = client_findbymachport(session);
394    if (!client ) {
395		*result = kSCStatusInvalidArgument;
396		goto failed;
397    }
398
399	if ((serv = findbyserviceID(client->serviceID)) == 0) {
400		*result = kSCStatusConnectionNoService;
401		goto failed;
402	}
403
404	if (scnc_copystatistics(serv, &reply, &replylen)) {
405		*result = kSCStatusFailed;
406		goto failed;
407	}
408
409	*statistics = reply;
410	*statistics_len = replylen;
411
412	*result = kSCStatusOK;
413    return (KERN_SUCCESS);
414
415failed:
416	*statistics = 0;
417	*statistics_len = 0;
418    return (KERN_SUCCESS);
419}
420
421/* -----------------------------------------------------------------------------
422----------------------------------------------------------------------------- */
423__private_extern__
424kern_return_t
425_pppcontroller_copyuseroptions(mach_port_t session,
426		xmlDataOut_t * options,
427		mach_msg_type_number_t * options_len,
428		int * result)
429{
430	struct client		*client;
431	struct service		*serv = 0;
432	void				*reply = 0;
433	u_int16_t			replylen = 0;
434
435    client = client_findbymachport(session);
436    if (!client ) {
437		*result = kSCStatusInvalidArgument;
438		goto failed;
439    }
440
441	if ((serv = findbyserviceID(client->serviceID)) == 0) {
442		*result = kSCStatusConnectionNoService;
443		goto failed;
444	}
445
446	if (scnc_getconnectdata(serv, &reply, &replylen, 0)) {
447		*result = kSCStatusFailed;
448		goto failed;
449	}
450
451	*options = reply;
452	*options_len = replylen;
453
454	*result = kSCStatusOK;
455    return (KERN_SUCCESS);
456
457failed:
458	*options = 0;
459	*options_len = 0;
460    return (KERN_SUCCESS);
461}
462
463/* -----------------------------------------------------------------------------
464----------------------------------------------------------------------------- */
465__private_extern__
466kern_return_t
467_pppcontroller_start(mach_port_t session,
468				xmlData_t dataRef,		/* raw XML bytes */
469				mach_msg_type_number_t dataLen,
470				int linger,
471				int * result)
472{
473	struct client		*client;
474	struct service		*serv = 0;
475	CFDictionaryRef		optRef = 0;
476	int					err;
477
478	client = client_findbymachport(session);
479	if (!client ) {
480		*result = kSCStatusInvalidArgument;
481		goto failed;
482	}
483
484	if ((serv = findbyserviceID(client->serviceID)) == 0) {
485		*result = kSCStatusConnectionNoService;
486		goto failed;
487	}
488
489	/* un-serialize the user options */
490	if (dataLen) {
491		if (!_SCUnserialize((CFPropertyListRef *)&optRef, NULL, (void *)dataRef, dataLen)) {
492			*result = kSCStatusFailed;
493			goto failed;
494		}
495
496		if (!isA_CFDictionary(optRef)) {
497			*result = kSCStatusInvalidArgument;
498			goto failed;
499		}
500	}
501
502	if (optRef && !(client->has_machport_priv)){
503		SCLog(TRUE, LOG_ERR, CFSTR("SCNC Controller: _pppcontroller_start has no mach port priv"));
504		*result = kSCStatusFailed;
505		goto failed;
506	}
507
508	err = scnc_start(serv, optRef, client, linger ? 0 : 1, client->uid, client->gid, client->pid, client->bootstrap_port, client->au_session);
509	if (err) {
510		*result = kSCStatusFailed;
511		goto failed;
512	}
513
514	my_CFRelease(&optRef);
515	*result = kSCStatusOK;
516
517	return (KERN_SUCCESS);
518
519failed:
520	my_CFRelease(&optRef);
521	return (KERN_SUCCESS);
522}
523
524/* -----------------------------------------------------------------------------
525----------------------------------------------------------------------------- */
526__private_extern__
527kern_return_t
528_pppcontroller_stop(mach_port_t session,
529				int		force,
530				int		*result)
531{
532	struct client		*client, *arb_client;
533	struct service		*serv = 0;
534	int                  scnc_reason;
535
536	client = client_findbymachport(session);
537	if (!client ) {
538		    *result = kSCStatusInvalidArgument;
539		    goto failed;
540	}
541
542	if ((serv = findbyserviceID(client->serviceID)) == 0) {
543		*result = kSCStatusConnectionNoService;
544		goto failed;
545	}
546	arb_client = force ? 0 : client;
547	scnc_reason = arb_client? SCNC_STOP_USER_REQ : SCNC_STOP_USER_REQ_NO_CLIENT;
548
549	if (controller_options_is_onDemandAutoPauseUponDisconnect()) {
550		if (serv->ondemand_paused == ONDEMAND_PAUSE_STATE_TYPE_OFF) {
551			/* a disconnect on a VOD service will cause VOD to pause until network change */
552			ondemand_set_pause(serv, ONDEMAND_PAUSE_STATE_TYPE_UNTIL_NETCHANGE, FALSE);
553		}
554	}
555
556	scnc_stop(serv, client, SIGHUP, scnc_reason);
557
558	*result = kSCStatusOK;
559	return (KERN_SUCCESS);
560
561failed:
562	return (KERN_SUCCESS);
563}
564
565
566/* -----------------------------------------------------------------------------
567----------------------------------------------------------------------------- */
568__private_extern__
569kern_return_t
570_pppcontroller_ondemand_refresh_state(mach_port_t session,
571				      int *result)
572{
573    *result = kSCStatusOK;
574
575    check_network_refresh();
576
577    return (KERN_SUCCESS);
578}
579
580/* -----------------------------------------------------------------------------
581----------------------------------------------------------------------------- */
582__private_extern__
583kern_return_t
584_pppcontroller_suspend(mach_port_t session,
585				int		*result)
586{
587	struct client		*client;
588	struct service		*serv = 0;
589
590    client = client_findbymachport(session);
591    if (!client ) {
592		*result = kSCStatusInvalidArgument;
593		goto failed;
594    }
595
596	if ((serv = findbyserviceID(client->serviceID)) == 0) {
597		*result = kSCStatusConnectionNoService;
598		goto failed;
599	}
600
601    scnc_suspend(serv);
602
603	*result = kSCStatusOK;
604    return (KERN_SUCCESS);
605
606failed:
607    return (KERN_SUCCESS);
608}
609
610/* -----------------------------------------------------------------------------
611----------------------------------------------------------------------------- */
612__private_extern__
613kern_return_t
614_pppcontroller_resume(mach_port_t session,
615				int		*result)
616{
617	struct client		*client;
618	struct service		*serv = 0;
619
620    client = client_findbymachport(session);
621    if (!client ) {
622		*result = kSCStatusInvalidArgument;
623		goto failed;
624    }
625
626	if ((serv = findbyserviceID(client->serviceID)) == 0) {
627		*result = kSCStatusConnectionNoService;
628		goto failed;
629	}
630
631    scnc_resume(serv);
632
633	*result = kSCStatusOK;
634    return (KERN_SUCCESS);
635
636failed:
637    return (KERN_SUCCESS);
638}
639
640/* -----------------------------------------------------------------------------
641----------------------------------------------------------------------------- */
642__private_extern__
643kern_return_t
644_pppcontroller_notification(mach_port_t session,
645			 int enable,
646		     int * result)
647{
648	struct client		*client;
649
650    client = client_findbymachport(session);
651    if (!client ) {
652		*result = kSCStatusInvalidArgument;
653		goto failed;
654    }
655
656	if (enable) {
657		client->flags |= CLIENT_FLAG_NOTIFY_STATUS;
658	}
659	else {
660		client->flags &= ~CLIENT_FLAG_NOTIFY_STATUS;
661	}
662
663	*result = kSCStatusOK;
664    return (KERN_SUCCESS);
665
666failed:
667    return (KERN_SUCCESS);
668}
669
670/* -----------------------------------------------------------------------------
671----------------------------------------------------------------------------- */
672__private_extern__
673kern_return_t
674_pppcontroller_bootstrap(mach_port_t server,
675		mach_port_t *bootstrap,
676		mach_port_t *au_session,
677		int * result,
678		audit_token_t *audit_token)
679{
680	int                 pid;
681	struct service		*serv;
682
683	audit_token_to_au32(*audit_token,
684			    NULL,			// auidp
685			    NULL,			// euid
686			    NULL,			// egid
687			    NULL,			// ruid
688			    NULL,			// rgid
689			    &pid,			// pid
690			    NULL,			// asid
691			    NULL);			// tid
692
693	if ((serv = findbypid(pid)) == 0) {
694		*result = kSCStatusInvalidArgument;
695		goto failed;
696	}
697
698	*bootstrap = serv->bootstrap;
699	*au_session = serv->au_session;
700
701#if !TARGET_OS_IPHONE
702#endif
703
704	*result = kSCStatusOK;
705
706	return (KERN_SUCCESS);
707
708failed:
709	*bootstrap = MACH_PORT_NULL;
710	*au_session = MACH_PORT_NULL;
711	return (KERN_SUCCESS);
712}
713
714/* -----------------------------------------------------------------------------
715----------------------------------------------------------------------------- */
716__private_extern__
717kern_return_t
718_pppcontroller_copyprivoptions(mach_port_t server,
719		int options_type,
720		xmlDataOut_t * options,
721		mach_msg_type_number_t * options_len,
722		int * result,
723		audit_token_t *audit_token)
724{
725    int                 pid;
726	struct service		*serv;
727	void				*reply = 0;
728	u_int16_t			replylen = 0;
729
730	audit_token_to_au32(*audit_token,
731			    NULL,			// auidp
732			    NULL,			// euid
733			    NULL,			// egid
734			    NULL,			// ruid
735			    NULL,			// rgid
736			    &pid,			// pid
737			    NULL,			// asid
738			    NULL);			// tid
739
740	if ((serv = findbypid(pid)) == 0) {
741		*result = kSCStatusInvalidArgument;
742		goto failed;
743	}
744
745	switch (options_type) {
746
747		/* system options */
748		case 0:
749			if (scnc_getconnectsystemdata(serv, &reply, &replylen)) {
750				*result = kSCStatusFailed;
751				goto failed;
752			}
753			break;
754
755		/* user options */
756		case 1:
757
758			if (scnc_getconnectdata(serv, &reply, &replylen, 1)) {
759				*result = kSCStatusFailed;
760				goto failed;
761			}
762			break;
763	}
764
765	*options = reply;
766	*options_len = replylen;
767
768	*result = kSCStatusOK;
769
770    return (KERN_SUCCESS);
771
772failed:
773	*options = 0;
774	*options_len = 0;
775    return (KERN_SUCCESS);
776}
777
778/* -----------------------------------------------------------------------------
779----------------------------------------------------------------------------- */
780__private_extern__
781kern_return_t
782_pppcontroller_iscontrolled(mach_port_t server,
783				int * result,
784				audit_token_t *audit_token)
785{
786    pid_t                pid = 0;
787	struct service		*serv;
788
789	audit_token_to_au32(*audit_token,
790			    NULL,			// auidp
791			    NULL,			// euid
792			    NULL,			// egid
793			    NULL,			// ruid
794			    NULL,			// rgid
795			    &pid,			// pid
796			    NULL,			// asid
797			    NULL);			// tid
798
799	if ((serv = findbypid(pid)) == 0)
800		*result = kSCStatusInvalidArgument;
801	else
802		*result = kSCStatusOK;
803
804    return (KERN_SUCCESS);
805}
806
807
808/* -----------------------------------------------------------------------------
809----------------------------------------------------------------------------- */
810static Boolean
811hasEntitlement(audit_token_t audit_token, CFStringRef entitlement, CFStringRef vpntype)
812{
813	Boolean		hasEntitlement	= FALSE;
814	SecTaskRef	task;
815
816	/* Create the security task from the audit token. */
817	task = SecTaskCreateWithAuditToken(NULL, audit_token);
818	if (task != NULL) {
819		CFErrorRef	error	= NULL;
820		CFTypeRef	value;
821
822		/* Get the value for the entitlement. */
823		value = SecTaskCopyValueForEntitlement(task, entitlement, &error);
824		if (value != NULL) {
825			if (isA_CFBoolean(value)) {
826				if (CFBooleanGetValue(value)) {
827					/* if client DOES have entitlement */
828					hasEntitlement = TRUE;
829				}
830			} else if (isA_CFArray(value)){
831				if (vpntype == NULL){
832					/* we don't care about subtype */
833					hasEntitlement = TRUE;
834				}else {
835					if (CFArrayContainsValue(value,
836											 CFRangeMake(0, CFArrayGetCount(value)),
837											 vpntype)) {
838						// if client DOES have entitlement
839						hasEntitlement = TRUE;
840					}
841				}
842			} else {
843				SCLog(TRUE, LOG_ERR,
844				      CFSTR("SCNC Controller: entitlement not valid: %@"),
845				      entitlement);
846			}
847
848			CFRelease(value);
849		} else if (error != NULL) {
850			SCLog(TRUE, LOG_ERR,
851			      CFSTR("SCNC Controller: SecTaskCopyValueForEntitlement() failed, error=%@: %@"),
852			      error,
853			      entitlement);
854			CFRelease(error);
855		}
856
857		CFRelease(task);
858	} else {
859		SCLog(TRUE, LOG_ERR,
860		      CFSTR("SCNC Controller: SecTaskCreateWithAuditToken() failed: %@"),
861		      entitlement);
862	}
863
864	return hasEntitlement;
865}
866
867
868/* -----------------------------------------------------------------------------
869----------------------------------------------------------------------------- */
870void mach_client_notify (mach_port_t port, CFStringRef serviceID, u_long event, u_long error)
871{
872	mach_msg_empty_send_t	msg;
873	kern_return_t			status;
874
875	/* Post notification as mach message */
876	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
877	msg.header.msgh_size = sizeof(msg);
878	msg.header.msgh_remote_port = port;
879	msg.header.msgh_local_port = MACH_PORT_NULL;
880	msg.header.msgh_id = 0;
881	status = mach_msg(&msg.header,		/* msg */
882			  MACH_SEND_MSG|MACH_SEND_TIMEOUT,	/* options */
883			  msg.header.msgh_size,		/* send_size */
884			  0,						/* rcv_size */
885			  MACH_PORT_NULL,			/* rcv_name */
886			  0,						/* timeout */
887			  MACH_PORT_NULL);			/* notify */
888
889	if (status == MACH_SEND_TIMEOUT)
890		mach_msg_destroy(&msg.header);
891}
892
893
894/* -----------------------------------------------------------------------------
895----------------------------------------------------------------------------- */
896static boolean_t
897process_notification(mach_msg_header_t * request)
898{
899	struct client		*client;
900
901    mach_no_senders_notification_t * notify;
902
903    notify = (mach_no_senders_notification_t *)request;
904    if ((notify->not_header.msgh_id > MACH_NOTIFY_LAST) ||
905		(notify->not_header.msgh_id < MACH_NOTIFY_FIRST)) {
906		return FALSE;	/* if this is not a notification message */
907	}
908    switch (notify->not_header.msgh_id) {
909		case MACH_NOTIFY_NO_SENDERS: {
910			mach_port_t	session	= notify->not_header.msgh_local_port;
911
912			client = client_findbymachport(session);
913			if (client) {
914				client_dispose(client);
915			}
916
917			/*
918			 * Our send right has already been removed. Remove our
919			 * receive right.
920			 */
921			mach_port_mod_refs(mach_task_self(),
922							   session,
923							   MACH_PORT_RIGHT_RECEIVE,
924							   -1);
925			break;
926		}
927		default :
928			break;
929    }
930    return (TRUE);
931}
932
933/* -----------------------------------------------------------------------------
934----------------------------------------------------------------------------- */
935void
936server_handle_request(CFMachPortRef port, void *msg, CFIndex size, void *info)
937{
938    mach_msg_return_t 	r;
939    mach_msg_header_t *	request = (mach_msg_header_t *)msg;
940    mach_msg_header_t *	reply;
941    static char		reply_s[PPP_MACH_MAX_INLINE_DATA * 4] __attribute__ ((aligned (4)));		// Wcast-align fix - force alignment
942
943    if (process_notification(request) == FALSE) {
944		if (_pppcontroller_subsystem.maxsize > sizeof(reply_s)) {
945			syslog(LOG_ERR, "PPPController: %d > %ld",
946				_pppcontroller_subsystem.maxsize, sizeof(reply_s));
947			reply = (mach_msg_header_t *)
948			malloc(_pppcontroller_subsystem.maxsize);
949		}
950		else {
951			reply = ALIGNED_CAST(mach_msg_header_t *)reply_s;
952		}
953		if (pppcontroller_server(request, reply) == FALSE) {
954			syslog(LOG_INFO, "unknown message ID (%d) received",
955			   request->msgh_id);
956			mach_msg_destroy(request);
957		}
958		else {
959			int		options;
960
961			options = MACH_SEND_MSG;
962			if (MACH_MSGH_BITS_REMOTE(reply->msgh_bits) == MACH_MSG_TYPE_MOVE_SEND) {
963				options |= MACH_SEND_TIMEOUT;
964			}
965			r = mach_msg(reply,
966				 options,
967				 reply->msgh_size,
968				 0,
969				 MACH_PORT_NULL,
970				 MACH_MSG_TIMEOUT_NONE,
971				 MACH_PORT_NULL);
972			if (r != MACH_MSG_SUCCESS) {
973				syslog(LOG_INFO, "PPPController: mach_msg(send): %s",
974					mach_error_string(r));
975				mach_msg_destroy(reply);
976			}
977		}
978		if (reply != ALIGNED_CAST(mach_msg_header_t *)reply_s) {
979			free(reply);
980		}
981    }
982    return;
983}
984
985/* -----------------------------------------------------------------------------
986 ----------------------------------------------------------------------------- */
987static CFStringRef
988serverMPCopyDescription(const void *info)
989{
990	return CFStringCreateWithFormat(NULL, NULL, CFSTR("PPPController"));
991}
992
993/* -----------------------------------------------------------------------------
994 ----------------------------------------------------------------------------- */
995static CFStringRef
996serverMPCopyDescriptionPriv(const void *info)
997{
998	return CFStringCreateWithFormat(NULL, NULL, CFSTR("PPPController-Priv"));
999}
1000
1001/* -----------------------------------------------------------------------------
1002 ----------------------------------------------------------------------------- */
1003int
1004ppp_mach_start_server_priv()
1005{
1006    kern_return_t 	status;
1007    CFRunLoopSourceRef	rls;
1008	mach_port_t         our_port = MACH_PORT_NULL;
1009	CFMachPortContext   context  = { 0, (void *)2, NULL, NULL, serverMPCopyDescriptionPriv };
1010
1011	status = bootstrap_check_in(bootstrap_port, PPPCONTROLLER_SERVER_PRIV, &our_port);
1012	if (status != BOOTSTRAP_SUCCESS) {
1013		SCLog(TRUE, LOG_ERR, CFSTR("PPPController: bootstrap_check_in \"%s\" error = %s"),
1014			  PPPCONTROLLER_SERVER, bootstrap_strerror(status));
1015		return -1;
1016	}
1017
1018	gServer_cfport_priv = _SC_CFMachPortCreateWithPort("PPPController", our_port, server_handle_request, &context);
1019	if (!gServer_cfport_priv) {
1020		SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create priv mach port"));
1021		return -1;
1022	}
1023    gServer_machport_priv = our_port;
1024	rls = CFMachPortCreateRunLoopSource(0, gServer_cfport_priv, 0);
1025	if (!rls) {
1026		SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create rls"));
1027		CFRelease(gServer_cfport_priv);
1028		gServer_cfport_priv = NULL;
1029        gServer_machport_priv = NULL;
1030		return -1;
1031	}
1032
1033	gControllerRunloop = CFRunLoopGetCurrent();
1034	CFRunLoopAddSource(gControllerRunloop, rls, kCFRunLoopDefaultMode);
1035	CFRunLoopAddSource(gControllerRunloop, gTerminalrls, kCFRunLoopDefaultMode);
1036    CFRelease(rls);
1037	return 0;
1038
1039}
1040
1041/* -----------------------------------------------------------------------------
1042----------------------------------------------------------------------------- */
1043int
1044ppp_mach_start_server()
1045{
1046    kern_return_t 	status;
1047    CFRunLoopSourceRef	rls;
1048	mach_port_t      our_port = MACH_PORT_NULL;
1049	CFMachPortContext      context  = { 0, (void *)1, NULL, NULL, serverMPCopyDescription };
1050
1051	status = bootstrap_check_in(bootstrap_port, PPPCONTROLLER_SERVER, &our_port);
1052	if (status != BOOTSTRAP_SUCCESS) {
1053		SCLog(TRUE, LOG_ERR, CFSTR("PPPController: bootstrap_check_in \"%s\" error = %s"),
1054			  PPPCONTROLLER_SERVER, bootstrap_strerror(status));
1055		return -1;
1056	}
1057
1058	gServer_cfport = _SC_CFMachPortCreateWithPort("PPPController", our_port, server_handle_request, &context);
1059	if (!gServer_cfport) {
1060		SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create mach port"));
1061		return -1;
1062	}
1063
1064    gServer_machport = our_port;
1065
1066	rls = CFMachPortCreateRunLoopSource(0, gServer_cfport, 0);
1067	if (!rls) {
1068		SCLog(TRUE, LOG_ERR, CFSTR("PPPController: cannot create rls"));
1069		CFRelease(gServer_cfport);
1070		gServer_cfport = NULL;
1071        gServer_machport = NULL;
1072		return -1;
1073	}
1074
1075	gControllerRunloop = CFRunLoopGetCurrent();
1076	CFRunLoopAddSource(gControllerRunloop, rls, kCFRunLoopDefaultMode);
1077	CFRunLoopAddSource(gControllerRunloop, gTerminalrls, kCFRunLoopDefaultMode);
1078    CFRelease(rls);
1079
1080	return 0;
1081
1082}
1083