1/* 2 * Copyright (c) 2000-2003 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 * 26 * Theory of operation : 27 * 28 * PPTP plugin for vpnd 29 * 30----------------------------------------------------------------------------- */ 31 32/* ----------------------------------------------------------------------------- 33 Includes 34----------------------------------------------------------------------------- */ 35 36#include <stdio.h> 37#include <ctype.h> 38#include <stdlib.h> 39#include <string.h> 40#include <unistd.h> 41#include <signal.h> 42#include <errno.h> 43#include <fcntl.h> 44#include <syslog.h> 45#include <netdb.h> 46#include <pwd.h> 47#include <setjmp.h> 48#include <sys/param.h> 49#include <sys/types.h> 50#include <sys/wait.h> 51#include <sys/time.h> 52#include <sys/resource.h> 53#include <sys/socket.h> 54#include <sys/stat.h> 55#include <sys/socket.h> 56#include <netinet/in.h> 57#include <arpa/inet.h> 58#include <syslog.h> 59#include <sys/ioctl.h> 60#include <net/if.h> 61#include <net/route.h> 62#include <pthread.h> 63#include <sys/kern_event.h> 64#include <netinet/in_var.h> 65#include <CoreFoundation/CFNumber.h> 66#include <CoreFoundation/CFBundle.h> 67#include <SystemConfiguration/SystemConfiguration.h> 68 69#include "../../../Helpers/vpnd/vpnplugins.h" 70#include "../../../Helpers/vpnd/vpnd.h" 71#include "../PPTP-extension/PPTP.h" 72#include "../PPTP-plugin/pptp.h" 73 74 75 76// ---------------------------------------------------------------------------- 77// � Private Globals 78// ---------------------------------------------------------------------------- 79static CFBundleRef bundle = 0; 80static int listen_sockfd = -1; 81 82int pptpvpn_get_pppd_args(struct vpn_params *params, int reload); 83int pptpvpn_listen(void); 84int pptpvpn_accept(void); 85int pptpvpn_refuse(void); 86void pptpvpn_close(void); 87 88static u_long load_kext(char *kext, int byBundleID); 89 90 91/* ----------------------------------------------------------------------------- 92plugin entry point, called by vpnd 93ref is the vpn bundle reference 94pppref is the ppp bundle reference 95bundles can be layout in two different ways 96- As simple vpn bundles (bundle.vpn). the bundle contains the vpn bundle binary. 97- As full ppp bundles (bundle.ppp). The bundle contains the ppp bundle binary, 98and also the vpn kext and the vpn bundle binary in its Plugins directory. 99if a simple vpn bundle was used, pppref will be NULL. 100if a ppp bundle was used, the vpn plugin will be able to get access to the 101Plugins directory and load the vpn kext. 102----------------------------------------------------------------------------- */ 103int start(struct vpn_channel* the_vpn_channel, CFBundleRef ref, CFBundleRef pppref, int debug, int log_verbose) 104{ 105 int s; 106 char name[MAXPATHLEN]; 107 CFURLRef url; 108 109 /* first load the kext if we are loaded as part of a ppp bundle */ 110 if (pppref) { 111 s = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_PPTP); 112 if (s < 0) { 113 if ((url = CFBundleCopyBundleURL(pppref))) { 114 name[0] = 0; 115 CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)name, MAXPATHLEN - 1); 116 CFRelease(url); 117 strlcat(name, "/", sizeof(name)); 118 if ((url = CFBundleCopyBuiltInPlugInsURL(pppref))) { 119 CFURLGetFileSystemRepresentation(url, 0, (UInt8 *)(name + strlen(name)), 120 MAXPATHLEN - strlen(name) - strlen(PPTP_NKE) - 1); 121 CFRelease(url); 122 strlcat(name, "/", sizeof(name)); 123 strlcat(name, PPTP_NKE, sizeof(name)); 124#if !TARGET_OS_EMBEDDED // This file is not built for Embedded 125 if (!load_kext(name, 0)) 126#else 127 if (!load_kext(PPTP_NKE_ID, 1)) 128#endif 129 s = socket(PF_PPP, SOCK_DGRAM, PPPPROTO_PPTP); 130 } 131 } 132 if (s < 0) { 133 vpnlog(LOG_ERR, "PPTP plugin: Unable to load PPTP kernel extension\n"); 134 return -1; 135 } 136 } 137 close (s); 138 } 139 140 /* retain reference */ 141 bundle = ref; 142 CFRetain(bundle); 143 144 // hookup our socket handlers 145 bzero(the_vpn_channel, sizeof(struct vpn_channel)); 146 the_vpn_channel->get_pppd_args = pptpvpn_get_pppd_args; 147 the_vpn_channel->listen = pptpvpn_listen; 148 the_vpn_channel->accept = pptpvpn_accept; 149 the_vpn_channel->refuse = pptpvpn_refuse; 150 the_vpn_channel->close = pptpvpn_close; 151 152 return 0; 153} 154 155/* ----------------------------------------------------------------------------- 156 pptpvpn_get_pppd_args 157----------------------------------------------------------------------------- */ 158int pptpvpn_get_pppd_args(struct vpn_params *params, int reload) 159{ 160 if (params->serverRef) 161 /* arguments from the preferences file */ 162 addstrparam(params->exec_args, ¶ms->next_arg_index, "pptpmode", "answer"); 163 164 return 0; 165} 166 167 168/* ----------------------------------------------------------------------------- 169 system call wrappers 170----------------------------------------------------------------------------- */ 171int pptp_sys_accept(int sockfd, struct sockaddr *cliaddr, int *addrlen) 172{ 173 int fd; 174 175 while ((fd = accept(sockfd, cliaddr, (uint32_t *)addrlen)) == -1) 176 if (errno != EINTR) { 177 vpnlog(LOG_ERR, "PPTP plugin: error calling accept = %s\n", strerror(errno)); 178 return -1; 179 } 180 return fd; 181} 182 183int pptp_sys_close(int sockfd) 184{ 185 while (close(sockfd) == -1) 186 if (errno != EINTR) { 187 vpnlog(LOG_ERR, "PPTP plugin: error calling close on socket = %s\n", strerror(errno)); 188 return -1; 189 } 190 return 0; 191} 192 193 194/* ----------------------------------------------------------------------------- 195 closeall 196----------------------------------------------------------------------------- */ 197static void closeall() 198{ 199 int i; 200 201 for (i = getdtablesize() - 1; i >= 0; i--) close(i); 202 open("/dev/null", O_RDWR, 0); 203 dup(0); 204 dup(0); 205 return; 206} 207 208 209/* ----------------------------------------------------------------------------- 210 load_kext 211----------------------------------------------------------------------------- */ 212u_long load_kext(char *kext, int byBundleID) 213{ 214 int pid; 215 216 if ((pid = fork()) < 0) 217 return 1; 218 219 if (pid == 0) { 220 closeall(); 221 // PPP kernel extension not loaded, try load it... 222 if (byBundleID) 223 execle("/sbin/kextload", "kextload", "-b", kext, (char *)0, (char *)0); 224 else 225 execle("/sbin/kextload", "kextload", kext, (char *)0, (char *)0); 226 exit(1); 227 } 228 229 while (waitpid(pid, 0, 0) < 0) { 230 if (errno == EINTR) 231 continue; 232 return 1; 233 } 234 return 0; 235} 236 237/* ----------------------------------------------------------------------------- 238 pptpvpn_listen() called by vpnd to setup listening socket 239----------------------------------------------------------------------------- */ 240int pptpvpn_listen(void) 241{ 242 243 struct sockaddr_in addrListener; 244 int val; 245 246 // Create the requested socket 247 while ((listen_sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) 248 if (errno != EINTR) { 249 vpnlog(LOG_ERR, "PPTP plugin: Could not create socket - err = %s\n", strerror(errno)); 250 return -1 ; 251 } 252 253 // Don't want children to have a copy of this. 254// while (fcntl(listen_sockfd, F_SETFD, 1) == -1) 255// if (errno != EINTR) { 256// syslog(LOG_ERR, "VPND PPTP plugin: error calling fcntl = %s\n", strerror(errno)); 257// return -1; 258// } 259 260 addrListener.sin_family = AF_INET; 261 addrListener.sin_addr.s_addr = htonl(INADDR_ANY); 262 addrListener.sin_port = htons(PPTP_TCP_PORT); 263 264 val = 1; 265 setsockopt(listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 266 267 while (bind(listen_sockfd, (struct sockaddr *) &addrListener, sizeof (addrListener)) < 0) 268 if (errno != EINTR) { 269 vpnlog(LOG_ERR, "PPTP plugin: Unable to bind socket to port %d - err = %s\n", 270 PPTP_TCP_PORT, strerror(errno)); 271 return -1; 272 } 273 274 while (listen(listen_sockfd, SOMAXCONN) < 0) 275 if (errno == EINTR) { 276 vpnlog(LOG_ERR, "PPTP plugin: error calling listen = %s\n", strerror(errno)); 277 return -1; 278 } 279 280 return listen_sockfd; 281} 282 283 284/* ----------------------------------------------------------------------------- 285 pptpvpn_accept() called by vpnd to listen for incomming connections. 286----------------------------------------------------------------------------- */ 287int pptpvpn_accept(void) 288{ 289 290 int fdConn; 291 struct sockaddr_storage ssSender; 292 struct sockaddr *sapSender = (struct sockaddr *)&ssSender; 293 int nSize = sizeof (ssSender); 294 295 if ((fdConn = pptp_sys_accept(listen_sockfd, sapSender, &nSize)) < 0) 296 return -1; 297 if (sapSender->sa_family != AF_INET) { 298 vpnlog(LOG_ERR, "PPTP plugin: Unexpected protocol family!\n"); 299 if (pptp_sys_close(fdConn) < 0) 300 return -1; 301 return 0; 302 } 303 304 return fdConn; 305} 306 307/* ----------------------------------------------------------------------------- 308 pptpvpn_refuse() called by vpnd to refuse incomming connections 309 310 return values: -1 error 311 0 handled - do not launch pppd 312----------------------------------------------------------------------------- */ 313int pptpvpn_refuse(void) 314{ 315 316 int fdConn; 317 struct sockaddr_storage ssSender; 318 struct sockaddr *sapSender = (struct sockaddr *)&ssSender; 319 int nSize = sizeof (ssSender); 320 321 if ((fdConn = pptp_sys_accept(listen_sockfd, sapSender, &nSize)) < 0) 322 return -1; 323 324 if (pptp_sys_close(fdConn) < 0) 325 return -1; 326 327 return 0; 328} 329 330/* ----------------------------------------------------------------------------- 331 pptpvpn_close() called by vpnd to close listening socket and cleanup. 332----------------------------------------------------------------------------- */ 333void pptpvpn_close(void) 334{ 335 if (listen_sockfd != -1) { 336 pptp_sys_close(listen_sockfd); 337 listen_sockfd = -1; 338 } 339} 340 341