1/*
2 * Copyright (c) 2000 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#include <stdio.h>
26#include <ctype.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <signal.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <syslog.h>
34#include <netdb.h>
35#include <paths.h>
36#include <sys/queue.h>
37
38#include <sys/param.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41#include <sys/time.h>
42#include <sys/resource.h>
43#include <sys/stat.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <net/if.h>
48
49#include <CoreFoundation/CoreFoundation.h>
50#include <SystemConfiguration/SystemConfiguration.h>
51#include "../../Family/if_ppplink.h"
52#include "../../Family/ppp_defs.h"
53
54#include "vpnd.h"
55#include "vpnoptions.h"
56#include "vpnplugins.h"
57#include "RASSchemaDefinitions.h"
58#include "cf_utils.h"
59
60static u_char *empty_str = (u_char*)"";
61
62static int process_interface_prefs(struct vpn_params *params);
63static int process_ipv4_prefs(struct vpn_params *params);
64static int process_ipv6_prefs(struct vpn_params *params);
65static int process_dns_prefs(struct vpn_params *params);
66static int process_ppp_prefs(struct vpn_params *params);
67
68//-----------------------------------------------------------------------------
69//	process_options
70//-----------------------------------------------------------------------------
71void ppp_process_options(struct vpn_params *params)
72{
73
74    params->plugin_path = 0;
75    params->serverSubTypeRef = 0;
76    params->server_subtype = PPP_TYPE_OTHER;
77}
78
79// ----------------------------------------------------------------------------
80//	process_prefs
81// ----------------------------------------------------------------------------
82int ppp_process_prefs(struct vpn_params *params)
83{
84
85    u_char 			pathStr[MAXPATHLEN];
86    u_int32_t		len;
87	int				i;
88
89    // clear the argument array
90    params->next_arg_index = 0;
91    for (i = 0; i < MAXARG; i++)
92        params->exec_args[i] = 0;
93
94    // add the pppd program name to the exec args
95    addparam(params->exec_args, &params->next_arg_index, PPPD_PRGM);
96
97    // add some general args that are always needed
98    addstrparam(params->exec_args, &params->next_arg_index, "serverid", params->server_id);	// server ID
99    addparam(params->exec_args, &params->next_arg_index, "nodetach");	// we don't want pppd to detach.
100    addparam(params->exec_args, &params->next_arg_index, "proxyarp");  	// we proxy for the client
101
102    // process the dictionaries
103    if (process_interface_prefs(params))
104        goto fail;
105    if (process_ipv4_prefs(params))
106        goto fail;
107    if (process_ipv6_prefs(params))
108        goto fail;
109    if (process_dns_prefs(params))
110        goto fail;
111    if (process_ppp_prefs(params))
112        goto fail;
113
114    // always try to use options defined in /etc/ppp/peers/[service provider]
115    // they can override what have been specified by the prefs file
116    // be careful to the conflicts on options
117	len = sizeof(pathStr);
118    get_str_option(params->serverRef, kRASEntPPP, kRASPropUserDefinedName, pathStr, sizeof(pathStr), &len, empty_str);
119    if (pathStr[0])
120        addstrparam(params->exec_args, &params->next_arg_index, "call", (char*)pathStr);
121
122    return 0;
123
124fail:
125    if (params->serverSubTypeRef) {
126        CFRelease(params->serverSubTypeRef);
127        params->serverSubTypeRef = 0;
128    }
129    return -1;
130}
131
132//-----------------------------------------------------------------------------
133//	process_interface_prefs
134//-----------------------------------------------------------------------------
135static int process_interface_prefs(struct vpn_params *params)
136{
137    CFDictionaryRef	dict;
138    int path_len = 0;
139
140    //  get type/subtype of server
141    dict = CFDictionaryGetValue(params->serverRef, kRASEntInterface);
142
143	// get server subtype and check if supported
144	params->serverSubTypeRef = CFDictionaryGetValue(dict, kRASPropInterfaceSubType);
145	if (!isString(params->serverSubTypeRef)) {
146		vpnlog(LOG_ERR, "Incorrect server subtype found\n");
147		params->serverSubTypeRef = NULL;
148		return -1;
149	}
150	path_len = CFStringGetLength(params->serverSubTypeRef) + 5;
151	params->plugin_path = malloc(path_len);
152	CFStringGetCString(params->serverSubTypeRef, params->plugin_path,
153						path_len, kCFStringEncodingUTF8);
154	strlcat(params->plugin_path, ".ppp", path_len);
155	if (!plugin_exists(params->plugin_path)) {
156		vpnlog(LOG_ERR, "Unsupported plugin '%s'\n", params->plugin_path);
157		params->serverSubTypeRef = NULL;
158		free(params->plugin_path);
159		params->plugin_path = NULL;
160		return -1;
161	}
162
163	// add the vpn protocol plugin parameter to the exec args
164	addstrparam(params->exec_args, &params->next_arg_index, "plugin", params->plugin_path);
165
166	if (CFStringCompare(params->serverSubTypeRef, kRASValInterfaceSubTypePPTP, 0) == kCFCompareEqualTo)
167		params->server_subtype = PPP_TYPE_PPTP;
168	else if (CFStringCompare(params->serverSubTypeRef, kRASValInterfaceSubTypeL2TP, 0) == kCFCompareEqualTo)
169		params->server_subtype = PPP_TYPE_L2TP;
170	else if (CFStringCompare(params->serverSubTypeRef, kRASValInterfaceSubTypePPPoE, 0) == kCFCompareEqualTo)
171		params->server_subtype = PPP_TYPE_PPPoE;
172	else if (CFStringCompare(params->serverSubTypeRef, kRASValInterfaceSubTypePPPSerial, 0) == kCFCompareEqualTo)
173		params->server_subtype = PPP_TYPE_SERIAL;
174	else
175		params->server_subtype = PPP_TYPE_OTHER;
176
177	CFRetain(params->serverSubTypeRef);
178
179    return 0;
180}
181
182//-----------------------------------------------------------------------------
183//	process_ipv4_prefs
184//-----------------------------------------------------------------------------
185static int process_ipv4_prefs(struct vpn_params *params)
186{
187    CFArrayRef		array = 0;
188    CFStringRef		ipstr = 0, ipstr2 = 0;
189    CFDictionaryRef	dict;
190    char 		str[MAXPATHLEN];
191    uint32_t 		i, nb, len;
192    char		ipcstr[100], ipcstr2[100], ip_addr[100], ip_addr2[100];
193    char		*ip, *ip2;
194
195    // Check if the IPv4 dictionary is present
196    if ((dict = CFDictionaryGetValue(params->serverRef, kRASEntIPv4)) && isDictionary(dict)) {
197
198        // get server side address
199		len = sizeof(str);
200        get_array_option(params->serverRef, kRASEntIPv4, kRASPropIPv4Addresses, 0, (u_char*)str, sizeof(str), &len, empty_str);
201        if (str[0] == 0) {
202            // get the address of the default interface
203            ipstr = CopyDefaultIPAddress();
204            if (ipstr) {
205                CFStringGetCString(ipstr, str, sizeof(str), kCFStringEncodingMacRoman);
206                CFRelease(ipstr);
207                ipstr = 0;
208            }
209        }
210        if (str[0]) {
211            strlcat(str, ":", sizeof(str));
212            addparam(params->exec_args, &params->next_arg_index, str);
213        }
214
215        // build client address list
216        if (isDictionary(dict)) {
217            /* individual ip addresses */
218            array  = CFDictionaryGetValue(dict, kRASPropIPv4DestAddresses);
219            if (isArray(array)) {
220
221                nb = CFArrayGetCount(array);
222                for (i = 0; i < nb; i++) {
223                    ipstr = CFArrayGetValueAtIndex(array, i);
224                    if (isString(ipstr)) {
225                        if (CFStringGetCString(ipstr, ipcstr, sizeof(ipcstr), kCFStringEncodingMacRoman)) {
226                            if ((ip = validate_ip_string(ipcstr, ip_addr, sizeof(ip_addr)))) {
227                                if (add_address(ip)) {
228                                    vpnlog(LOG_ERR, "Error while processing ip address %s\n", ip);
229                                    return -1;
230                                }
231                            } else
232                                vpnlog(LOG_ERR, "Ignoring invalid ip address %s\n", ipcstr);
233                        }
234                    }
235                }
236            }
237            // ip address ranges
238            array  = CFDictionaryGetValue(dict, kRASPropIPv4DestAddressRanges);
239            if (isArray(array)) {
240                if (CFArrayGetCount(array) % 2)
241                    vpnlog(LOG_ERR, "Error - ip address ranges must be in pairs\n");
242                else {
243                    nb = CFArrayGetCount(array);
244                    for (i = 0; i < nb; i += 2) {
245                        ipstr = CFArrayGetValueAtIndex(array, i);
246                        ipstr2 = CFArrayGetValueAtIndex(array, i+1);
247                        if (isString(ipstr) && isString(ipstr2)) {
248                            if (CFStringGetCString(ipstr, ipcstr, sizeof(ipcstr), kCFStringEncodingMacRoman) &&
249                                CFStringGetCString(ipstr2, ipcstr2, sizeof(ipcstr2), kCFStringEncodingMacRoman)) {
250                                ip = validate_ip_string(ipcstr, ip_addr, sizeof(ip_addr));
251                                ip2 = validate_ip_string(ipcstr2, ip_addr2, sizeof(ip_addr2));
252                                if (ip && ip2) {
253                                    if (add_address_range(ip, ip2)) {
254                                        vpnlog(LOG_ERR, "Error while processing ip address range %s\n", ip);
255                                        return -1;
256                                    }
257                                } else
258                                    vpnlog(LOG_ERR, "Ignoring invalid ip address range %s\n", ipcstr);
259                            }
260                        }
261                    }
262                }
263            }
264        }
265    }
266
267    if (!address_avail()) {
268        vpnlog(LOG_ERR, "No valid client IP addresses\n");
269        return -1;
270    }
271
272    return 0;
273
274}
275
276
277// ----------------------------------------------------------------------------
278//	process_ipv6_prefs
279// ----------------------------------------------------------------------------
280static int process_ipv6_prefs(struct vpn_params *params)
281{
282    CFDictionaryRef	dict;
283
284    // Check if the IPv6 dictionary is present
285    if ((dict = CFDictionaryGetValue(params->serverRef, kRASEntIPv6)) && isDictionary(dict)) {
286        addparam(params->exec_args, &params->next_arg_index, "+ipv6");
287        addparam(params->exec_args, &params->next_arg_index, "ipv6cp-use-persistent");
288    }
289    return 0;
290}
291
292// ----------------------------------------------------------------------------
293//	process_dns_prefs
294// ----------------------------------------------------------------------------
295static int process_dns_prefs(struct vpn_params *params)
296{
297    CFPropertyListRef	ref = 0;
298    CFDictionaryRef	dict;
299    CFStringRef		key = 0;
300    CFArrayRef		array;
301    CFStringRef		addr;
302
303    char 		str[OPT_STR_LEN];
304    int			count, i;
305
306    // Check if the IPv4 dictionary is present
307    if (isDictionary(CFDictionaryGetValue(params->serverRef, kRASEntIPv4))) {
308        // get the DNS address array from the plist for from the dynamic store
309        dict = CFDictionaryGetValue(params->serverRef, kSCEntNetDNS);
310        if (isDictionary(dict)) {
311            array = CFDictionaryGetValue(dict, kRASPropDNSOfferedServerAddresses);
312            if (isArray(array)) {
313                count = CFArrayGetCount(array);
314                if (count == 0) {		// array is present but empty - get addresses from dynamic store
315                    key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetDNS);
316                    if (key) {
317                        ref = SCDynamicStoreCopyValue(params->storeRef, key);
318                        if (isDictionary(ref)) {
319                            array = CFDictionaryGetValue(ref, kSCPropNetDNSServerAddresses);
320                            if (isArray(array))
321                                count = CFArrayGetCount(array);
322                        }
323                        CFRelease(key);
324                    }
325                }
326
327                for (i = 0; i < count && i < 2; i++) {
328                    addr = CFArrayGetValueAtIndex(array, i);
329                    if (isString(addr)) {
330                        str[0] = 0;
331                        CFStringGetCString(addr, str, OPT_STR_LEN, kCFStringEncodingUTF8);
332                        if (str[0])
333                            addstrparam(params->exec_args, &params->next_arg_index, "ms-dns", str);
334                    }
335                }
336                // free items from the store if required
337                if (ref)
338                    CFRelease(ref);
339            }
340        }
341    }
342
343    return 0;
344}
345
346// ----------------------------------------------------------------------------
347//	process_ppp_prefs
348// ----------------------------------------------------------------------------
349static int process_ppp_prefs(struct vpn_params *params)
350{
351    char 		pathStr[MAXPATHLEN], optStr[OPT_STR_LEN];
352    u_int32_t		len, lval, lval1, i;
353    CFDictionaryRef	dict;
354    CFArrayRef		array;
355    CFIndex		count;
356    CFStringRef		string;
357    int			noCCP;
358#define AUTH_BITS_PAP		0x1
359#define AUTH_BITS_CHAP		0x2
360#define AUTH_BITS_MSCHAP1	0x4
361#define AUTH_BITS_MSCHAP2	0x8
362#define AUTH_BITS_EAP		0x10
363    u_int32_t			auth_bits = 0; /* none */
364
365    //
366    // some basic admin options
367    //
368    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPVerboseLogging, &lval, 0);
369    if (lval)
370        addparam(params->exec_args, &params->next_arg_index, "debug");
371
372	len = sizeof(optStr);
373    get_str_option(params->serverRef, kRASEntPPP, kRASPropPPPLogfile, (u_char*)optStr, sizeof(optStr), &len, empty_str);
374    if (optStr[0]) {
375        // if logfile start with /, it's a full path
376        // otherwise it's relative to the logs folder (convention)
377        // we also strongly advise to name the file with the link number
378        // for example ppplog0
379        // the default path is /var/log
380        // it's useful to have the debug option with the logfile option
381        // with debug option, pppd will log the negociation
382        // debug option is different from kernel debug trace
383
384        snprintf(pathStr, sizeof(pathStr), "%s%s", optStr[0] == '/' ? "" : DIR_LOGS, optStr);
385        addstrparam(params->exec_args, &params->next_arg_index, "logfile", pathStr);
386    }
387
388    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPDisconnectOnIdle, &lval, 0);
389    if (lval) {
390        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPDisconnectOnIdleTimer, &lval, OPT_COMM_IDLETIMER_DEF);
391        if (lval) {
392            addintparam(params->exec_args, &params->next_arg_index, "idle", lval);
393            addparam(params->exec_args, &params->next_arg_index, "noidlesend");
394        }
395    }
396
397    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPUseSessionTimer, &lval, 0);
398    if (lval) {
399        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPSessionTimer, &lval, OPT_COMM_IDLETIMER_DEF);
400        if (lval)
401            addintparam(params->exec_args, &params->next_arg_index, "maxconnect", lval);
402    }
403
404    //
405    // LCP options
406    //
407    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPEchoEnabled, &lval, 0);
408    if (lval) {
409        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPEchoInterval, &lval, OPT_LCP_ECHOINTERVAL_DEF);
410        if (lval)
411            addintparam(params->exec_args, &params->next_arg_index, "lcp-echo-interval", lval);
412        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPEchoFailure, &lval, OPT_LCP_ECHOINTERVAL_DEF);
413        if (lval)
414            addintparam(params->exec_args, &params->next_arg_index, "lcp-echo-failure", lval);
415    }
416    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPCompressionACField, &lval, OPT_LCP_PCOMP_DEF);
417    if (lval == 0)
418        addparam(params->exec_args, &params->next_arg_index, "noaccomp");
419    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPCompressionPField, &lval, OPT_LCP_ACCOMP_DEF);
420    if (lval == 0)
421        addparam(params->exec_args, &params->next_arg_index, "nopcomp");
422
423    switch (params->server_subtype) {
424        case PPP_TYPE_PPPoE:
425            lval = OPT_LCP_MRU_PPPoE_DEF;
426            break;
427        case PPP_TYPE_PPTP:
428            lval = OPT_LCP_MRU_PPTP_DEF;
429            break;
430        case PPP_TYPE_L2TP:
431            lval = OPT_LCP_MRU_L2TP_DEF;
432            break;
433        default:
434            lval = OPT_LCP_MRU_DEF;
435    }
436    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPMRU, &lval, lval);
437    if (lval)
438        addintparam(params->exec_args, &params->next_arg_index, "mru", lval);
439
440    switch (params->server_subtype) {
441        case PPP_TYPE_PPPoE:
442            lval = OPT_LCP_MTU_PPPoE_DEF;
443            break;
444        case PPP_TYPE_PPTP:
445            lval = OPT_LCP_MTU_PPTP_DEF;
446            break;
447        case PPP_TYPE_L2TP:
448            lval = OPT_LCP_MTU_L2TP_DEF;
449            break;
450        default:
451            lval = OPT_LCP_MTU_DEF;
452    }
453    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPMTU, &lval, lval);
454    if (lval)
455        addintparam(params->exec_args, &params->next_arg_index, "mtu", lval);
456
457    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPReceiveACCM, &lval, OPT_LCP_RCACCM_DEF);
458    if (lval)
459        addintparam(params->exec_args, &params->next_arg_index, "asyncmap", lval);
460    else
461        addparam(params->exec_args, &params->next_arg_index, "receive-all");
462
463    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPLCPReceiveACCM, &lval, OPT_LCP_RCACCM_DEF);
464    if (lval) {
465        pathStr[0] = 0;
466        for (lval1 = 0; lval1 < 32; lval1++) {
467            if ((lval >> lval1) & 1) {
468                snprintf(optStr, sizeof(optStr), "%d,", lval1);
469                strlcat(pathStr, optStr, sizeof(pathStr));
470            }
471        }
472        pathStr[strlen(pathStr)-1] = 0; // remove last ','
473        addstrparam(params->exec_args, &params->next_arg_index, "escape", pathStr);
474    }
475
476    //
477    // IPCP options
478    //
479
480    // Check if the IPv4 dictionary is present
481    if (!(dict = CFDictionaryGetValue(params->serverRef, kRASEntIPv4))
482        || !isDictionary(dict)) {
483        addparam(params->exec_args, &params->next_arg_index, "noip");
484    }
485    else {
486
487        /* enforce the source ip address filtering */
488        addintparam(params->exec_args, &params->next_arg_index, "ip-src-address-filter",  NPAFMODE_SRC_IN);
489
490        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPIPCPCompressionVJ, &lval, OPT_IPCP_HDRCOMP_DEF);
491        if (lval == 0)
492            addparam(params->exec_args, &params->next_arg_index, "novj");
493    }
494
495    //
496    // CCP options
497    //
498    noCCP = 1;
499    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPCCPEnabled, &lval, 0);
500    if (lval) {
501        // Fix me : to enforce use of MS-CHAP, refuse any alteration of default auth proto
502        // a dialer specifying PAP or CHAP will works without CCP/MPPE
503        // even if CCP is enabled in the configuration.
504        // Will be revisited when addition compression modules and
505        // authentication modules will be added
506        //&& !ppp_getoptval(ppp, opts, PPP_OPT_AUTH_PROTO, &lval, sizeof(lval), &len, service)
507        //&& (lval == OPT_AUTH_PROTO_DEF)) {
508        if ((dict = CFDictionaryGetValue(params->serverRef, kRASEntPPP)) != 0) {
509            array = CFDictionaryGetValue(dict, kRASPropPPPCCPProtocols);
510            if (isArray(array)) {
511
512                int	mppe_found = 0;
513                count = CFArrayGetCount(array);
514                for (i = 0; i < count; i++) {
515                    string = CFArrayGetValueAtIndex(array, i);
516                    if (CFStringCompare(string, kRASValPPPCCPProtocolsMPPE, 0) == kCFCompareEqualTo) {
517                        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPMPPEKeySize128, &lval, 0);
518                        if (lval) {
519                            mppe_found = 1;
520                            addparam(params->exec_args, &params->next_arg_index, "mppe-128");
521                        }
522                        get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPMPPEKeySize40, &lval, 0);
523                        if (lval) {
524                            mppe_found = 1;
525                            addparam(params->exec_args, &params->next_arg_index, "mppe-40");
526                        }
527                    } else
528                        vpnlog(LOG_ERR, "Invalid compression type specified - ignored\n");
529                }
530                if (mppe_found) {
531                    noCCP = 0;
532                    addparam(params->exec_args, &params->next_arg_index, "mppe-stateless");
533                }
534            }
535        }
536    }
537    if (noCCP)	// no compression protocol
538        addparam(params->exec_args, &params->next_arg_index, "noccp");
539
540
541    //
542    // ACSP
543    //
544    get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPACSPEnabled, &lval, 0);
545    if (lval == 0)
546        addparam(params->exec_args, &params->next_arg_index, "noacsp");
547
548	get_int_option(params->serverRef, kRASEntPPP, kRASPropPPPInterceptDHCP, &lval, 1);
549	if (lval)
550		addparam(params->exec_args, &params->next_arg_index, "intercept-dhcp");
551
552
553    //
554    // Authentication
555    //
556
557    auth_bits = 0;
558	dict = CFDictionaryGetValue(params->serverRef, kRASEntPPP);
559    if (isDictionary(dict)) {
560        array = CFDictionaryGetValue(dict, kRASPropPPPAuthenticatorProtocol);
561        if (isArray(array)) {
562            count = CFArrayGetCount(array);
563
564			for (i = 0; i < count; i++) {
565				string = CFArrayGetValueAtIndex(array, i);
566				if (isString(string)) {
567					if (CFStringCompare(string, kRASValPPPAuthProtocolMSCHAP2, 0) == kCFCompareEqualTo)
568						auth_bits |= AUTH_BITS_MSCHAP2;
569					else if (CFStringCompare(string, kRASValPPPAuthProtocolMSCHAP1, 0) == kCFCompareEqualTo)
570						auth_bits |= AUTH_BITS_MSCHAP1;
571					else if (CFStringCompare(string, kRASValPPPAuthProtocolCHAP, 0) == kCFCompareEqualTo)
572						auth_bits |= AUTH_BITS_CHAP;
573					else if (CFStringCompare(string, kRASValPPPAuthProtocolPAP, 0) == kCFCompareEqualTo)
574						auth_bits |= AUTH_BITS_PAP;
575					else if (CFStringCompare(string, kRASValPPPAuthProtocolEAP, 0) == kCFCompareEqualTo)
576						auth_bits |= AUTH_BITS_EAP;
577					else {
578						vpnlog(LOG_ERR, "Unknown authentication type specified\n");
579						return -1;
580					}
581				}
582            }
583        }
584	}
585
586	if (auth_bits & AUTH_BITS_PAP)
587		addparam(params->exec_args, &params->next_arg_index, "require-pap");
588
589	if (auth_bits & AUTH_BITS_CHAP)
590		addparam(params->exec_args, &params->next_arg_index, "require-chap");
591
592	if (auth_bits & AUTH_BITS_MSCHAP1)
593		addparam(params->exec_args, &params->next_arg_index, "require-mschap");
594
595	if (auth_bits & AUTH_BITS_MSCHAP2)
596		addparam(params->exec_args, &params->next_arg_index, "require-mschap-v2");
597
598	if (auth_bits & AUTH_BITS_EAP) {
599
600		addparam(params->exec_args, &params->next_arg_index, "require-eap");
601
602		// add EAP plugins - must be at least one
603		int eapPluginFound = 0;
604
605		i = 0;
606		do {
607			lval = get_array_option(params->serverRef, kRASEntPPP, kRASPropPPPAuthenticatorEAPPlugins,
608									i++, (u_char*)pathStr, sizeof(pathStr), &len, empty_str);
609			if (pathStr[0]) {
610				strlcat(pathStr, ".ppp", sizeof(pathStr));	// add plugin suffix
611				if (!plugin_exists(pathStr)) {
612					vpnlog(LOG_ERR, "EAP plugin '%s' not found\n", pathStr);
613					return -1;
614				}
615				addstrparam(params->exec_args, &params->next_arg_index, "eapplugin", pathStr);
616				eapPluginFound = 1;
617			}
618		}
619		while (lval);
620
621		if (!eapPluginFound) {
622			 /* should check if Radius EAP proxy is enabled */
623			//vpnlog(LOG_ERR, "No EAP authentication plugin(s) specified\n");
624			//return -1;
625		}
626    }
627
628
629    //
630    // Plugins
631    //
632
633    // add authentication plugins
634    i = 0;
635    do {
636		len = sizeof(pathStr);
637       lval = get_array_option(params->serverRef, kRASEntPPP, kRASPropPPPAuthenticatorPlugins,
638							   i++, (u_char*)pathStr, sizeof(pathStr), &len, empty_str);
639        if (pathStr[0]) {
640            strlcat(pathStr, ".ppp", sizeof(pathStr));	// add plugin suffix
641            if (!plugin_exists(pathStr)) {
642                vpnlog(LOG_ERR, "Authentication plugin '%s' not found\n", pathStr);
643                return -1;
644            }
645            addstrparam(params->exec_args, &params->next_arg_index, "plugin", pathStr);
646        }
647    }
648    while (lval);
649
650    // add access control list plugins
651    i = 0;
652    do {
653 		len = sizeof(pathStr);
654       lval = get_array_option(params->serverRef, kRASEntPPP, kRASPropPPPAuthenticatorACLPlugins,
655							   i++, (u_char*)pathStr, sizeof(pathStr), &len, empty_str);
656        if (pathStr[0]) {
657            strlcat(pathStr, ".ppp", sizeof(pathStr));	// add plugin suffix
658            if (!plugin_exists(pathStr)) {
659                vpnlog(LOG_ERR, "Access Control plugin '%s' not found\n", pathStr);
660                return -1;
661            }
662            addstrparam(params->exec_args, &params->next_arg_index, "plugin2", pathStr);
663        }
664    }
665    while (lval);
666
667    // add any additional plugin we want to load
668    i = 0;
669    do {
670		len = sizeof(pathStr);
671        lval = get_array_option(params->serverRef, kRASEntPPP, kRASPropPPPPlugins,
672								i++, (u_char*)pathStr, sizeof(pathStr), &len, empty_str);
673        if (pathStr[0]) {
674            strlcat(pathStr, ".ppp", sizeof(pathStr));	// add plugin suffix
675            if (!plugin_exists(pathStr)) {
676                vpnlog(LOG_ERR, "Plugin '%s' not found\n", pathStr);
677                return -1;
678            }
679            addstrparam(params->exec_args, &params->next_arg_index, "plugin", pathStr);
680        }
681    }
682    while (lval);
683
684    return 0;
685}
686
687//-----------------------------------------------------------------------------
688//	check_conflicts
689//-----------------------------------------------------------------------------
690int ppp_check_conflicts(struct vpn_params *params)
691{
692
693    CFArrayRef			array;
694    CFStringRef			pattern, key;
695    CFStringRef			type, subtype;
696    CFPropertyListRef		ref;
697    int				count, i, ret = 0;
698    char			str[OPT_STR_LEN];
699
700    pattern = CFStringCreateWithFormat(0, 0, CFSTR("%@/%@/%@/%s/%@"), kSCDynamicStoreDomainState,
701                    kSCCompNetwork, kRASRemoteAccessServer, ".*", kRASEntInterface);
702
703    if (pattern) {
704        if ((array = SCDynamicStoreCopyKeyList(params->storeRef, pattern))) {
705            count = CFArrayGetCount(array);
706            for (i = 0; i < count; i++) {
707                key = CFArrayGetValueAtIndex(array, i);
708                if (key) {
709                    ref = SCDynamicStoreCopyValue(params->storeRef, key);
710                    if (isDictionary(ref)) {
711                        type = CFDictionaryGetValue(ref, kRASPropInterfaceType);
712                        subtype = CFDictionaryGetValue(ref, kRASPropInterfaceSubType);
713                        if (isString(type) && isString(subtype) &&
714                            (CFStringCompare(type, kRASValInterfaceTypePPP, 0) == kCFCompareEqualTo) &&
715                            (CFStringCompare(subtype, params->serverSubTypeRef, 0) == kCFCompareEqualTo)) {
716                            CFStringGetCString(subtype, str, OPT_STR_LEN, kCFStringEncodingMacRoman);
717                            vpnlog(LOG_ERR, "Server for subtype %s already running - vpnd launch failed.\n", str);
718                            ret = -1;
719                            CFRelease(ref);
720                            break;
721                        }
722                    }
723                    if (ref)
724                        CFRelease(ref);
725                }
726            }
727            CFRelease(array);
728        }
729        CFRelease(pattern);
730    }
731    return ret;
732}
733
734//-----------------------------------------------------------------------------
735//	kill_orphans
736//-----------------------------------------------------------------------------
737int ppp_kill_orphans(struct vpn_params* params)
738{
739
740    CFArrayRef			array;
741    CFStringRef			pattern, key;
742    CFMutableStringRef		mutable_key;
743    CFStringRef			server_id;
744    CFNumberRef			pidRef;
745    CFPropertyListRef		interface_dict, ppp_dict;
746    int				count, i, pid;
747    int				ret = 0;
748
749    pattern = CFStringCreateWithFormat(0, 0, CFSTR("%@/%@/%@/%s/%@"), kSCDynamicStoreDomainState,
750                    kSCCompNetwork, kSCCompService, ".*", kSCEntNetInterface);
751
752    if (pattern) {
753        if ((array = SCDynamicStoreCopyKeyList(params->storeRef, pattern))) {
754            count = CFArrayGetCount(array);
755            // for each pppd - check if server id is the same as ours
756            for (i = 0; i < count; i++) {
757                key = CFArrayGetValueAtIndex(array, i);
758                if (key) {
759                    interface_dict = SCDynamicStoreCopyValue(params->storeRef, key);
760                    if (isDictionary(interface_dict)) {
761                        server_id = CFDictionaryGetValue(interface_dict, CFSTR("ServerID"));
762                        if (isString(server_id) && CFStringCompare(server_id, params->serverIDRef, 0) == kCFCompareEqualTo) {
763                            // server id matches - get the pid and kill it
764                            mutable_key = CFStringCreateMutableCopy(0, 0, key);
765                            // modify the key to get the PPP dictionary
766                            if (CFStringFindAndReplace(mutable_key, kSCEntNetInterface, kSCEntNetPPP,
767                                    CFRangeMake(0, CFStringGetLength(mutable_key)), kCFCompareBackwards | kCFCompareAnchored)) {
768                                ppp_dict = SCDynamicStoreCopyValue(params->storeRef, mutable_key);
769                                if (isDictionary(ppp_dict)) {
770                                    pidRef = CFDictionaryGetValue(ppp_dict, CFSTR("pid"));
771                                    if (isNumber(pidRef))
772                                        if (CFNumberGetValue(pidRef, kCFNumberIntType, &pid))
773                                            ret = kill(pid, SIGTERM);
774                                }
775                                if (ppp_dict)
776                                    CFRelease(ppp_dict);
777                            }
778                            if (mutable_key)
779                                CFRelease(&mutable_key);
780                        }
781                    }
782                    if (interface_dict)
783                        CFRelease(interface_dict);
784                }
785            }
786            CFRelease(array);
787        }
788        CFRelease(pattern);
789    }
790    return ret;
791}
792