1/* 2 * Copyright (c) 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 * pptp.c 25 * ppp 26 * 27 * Created by Christophe Allie on Thu May 23 2002. 28 * Copyright (c) 2002 __MyCompanyName__. All rights reserved. 29 * 30 */ 31 32/* ----------------------------------------------------------------------------- 33 * 34 * Theory of operation : 35 * 36 * PPTP protocol speficic function for the pppd plugin. 37 * 38----------------------------------------------------------------------------- */ 39 40/* ----------------------------------------------------------------------------- 41 Includes 42----------------------------------------------------------------------------- */ 43 44#include <stdio.h> 45#include <ctype.h> 46#include <stdlib.h> 47#include <string.h> 48#include <unistd.h> 49#include <signal.h> 50#include <errno.h> 51#include <fcntl.h> 52#include <syslog.h> 53#include <netdb.h> 54#include <pwd.h> 55#include <setjmp.h> 56#include <sys/param.h> 57#include <sys/types.h> 58#include <sys/wait.h> 59#include <sys/time.h> 60#include <sys/resource.h> 61#include <sys/socket.h> 62#include <sys/stat.h> 63#include <sys/socket.h> 64#include <netinet/in.h> 65#include <arpa/inet.h> 66#include <syslog.h> 67#include <sys/ioctl.h> 68#include <net/dlil.h> 69#include <net/if.h> 70 71#include "../../../Helpers/pppd/pppd.h" 72#include "pptp.h" 73 74extern int kill_link; 75 76/* ----------------------------------------------------------------------------- 77 Definitions 78----------------------------------------------------------------------------- */ 79 80void pptp_received_echo_reply(u_int32_t identifier, u_int8_t result, u_int8_t error); 81 82char *control_msgs[] = { 83 "", /* 0 */ 84 "Start Control Connection Request", /* 1 */ 85 "Start Control Connection Reply", /* 2 */ 86 "Stop Control Connection Request", /* 3 */ 87 "Stop Control Connection Reply", /* 4 */ 88 "Echo Request", /* 5 */ 89 "Echo Reply", /* 6 */ 90 "Outgoing Call Request", /* 7 */ 91 "Outgoing Call Reply", /* 8 */ 92 "Incoming Call Request", /* 9 */ 93 "Incoming Call Reply", /* 10 */ 94 "Incoming Call Connected", /* 11 */ 95 "Call Clear Request", /* 12 */ 96 "Call Disconnect Notify", /* 14 */ 97 "Wan Error Notify", /* 14 */ 98 "Set Link Info" /* 15 */ 99}; 100 101/* ----------------------------------------------------------------------------- 102send a PPTP control request or reply 103----------------------------------------------------------------------------- */ 104int pptp_send(int fd, u_int16_t msg, void *req, u_int16_t reqlen, char *text) 105{ 106 u_char buf[256] __attribute__ ((aligned(4))); /* buffer large enough to send pptp control packets */ 107 struct pptp_header *hdr = ALIGNED_CAST(struct pptp_header *)buf; 108 int n, sent; 109 110 if ((sizeof(*hdr) + reqlen) > sizeof(buf)) { 111 // should not happen 112 error("PPTP length error when sending %s : %m\n", text); 113 return -1; 114 } 115 116 bzero(hdr, sizeof(*hdr)); 117 hdr->len = htons(sizeof(*hdr) + reqlen); 118 hdr->pptp_msgtype = htons(PPTP_CONTROL_MSG); 119 hdr->magic_cookie = htonl(PPTP_MAGIC_COOKIE); 120 hdr->ctrl_msgtype = htons(msg); 121 122 bcopy(req, buf + sizeof(*hdr), reqlen); 123 124 sent = 0; 125 while ((n = write(fd, buf + sent, ntohs(hdr->len) - sent)) != (ntohs(hdr->len) - sent)) { 126 if (n == -1 && errno != EINTR) { 127 error("PPTP error when sending %s : %m\n", text); 128 return -1; 129 } 130 if (kill_link) { 131 error("PPTP kill_link when sending\n"); 132 return -2; 133 } 134 if (n > 0) 135 sent += n; 136 } 137 138 return 0; 139} 140 141/* ----------------------------------------------------------------------------- 142----------------------------------------------------------------------------- */ 143int 144readn(int ref, void *data, int len) 145{ 146 int n, left = len; 147 void *p = data; 148 149 while (left > 0) { 150 if ((n = read(ref, p, left)) < 0) { 151 if (errno == EWOULDBLOCK) 152 return (len - left); 153 if (errno != EINTR) { 154 error("PPTP error when reading socket : %m\n"); 155 return -1; 156 } 157 n = 0; 158 } 159 else if (n == 0) { 160 error("PPTP error when reading socket : EOF\n"); 161 return -1; /* EOF */ 162 } 163 164 left -= n; 165 p += n; 166 } 167 return (len - left); 168} 169 170/* ----------------------------------------------------------------------------- 171receives a PPTP control reply 172----------------------------------------------------------------------------- */ 173int pptp_recv(int fd, u_int16_t msg, void *rep, u_int16_t replen, char *text) 174{ 175 struct pptp_header hdr; 176 int err; 177 178 if ((err = read(fd, &hdr, sizeof(hdr))) != sizeof(hdr)) { 179 if (kill_link) 180 return -2; 181 if (err == -1) 182 error("PPTP error when reading header for %s : %m\n", text); 183 return -1; 184 } 185 if (ntohs(hdr.ctrl_msgtype) != msg) { 186 error("PPTP didn't get %s (got message : %d)\n", text, hdr.ctrl_msgtype); 187 return -3; 188 } 189 if ((err = read(fd, rep, replen)) != replen) { 190 if (kill_link) 191 return -2; 192 if (err == -1) 193 error("PPTP error when reading %s : %m\n", text); 194 return -1; 195 } 196 return 0; 197} 198 199/* ----------------------------------------------------------------------------- 200----------------------------------------------------------------------------- */ 201int pptp_outgoing_call(int fd, 202 u_int16_t ourcallid, u_int16_t ourwindow, u_int16_t ourppd, 203 u_int16_t *peercallid, u_int16_t *peerwindow, u_int16_t *peerppd) 204{ 205 struct pptp_start_control_request ctl_req; 206 struct pptp_start_control_reply ctl_reply; 207 struct pptp_outgoing_call_request out_req; 208 struct pptp_outgoing_call_reply out_reply; 209 struct pptp_set_link_info link_info; 210 int err; 211 212 /* send the start request */ 213 bzero(&ctl_req, sizeof(ctl_req)); 214 ctl_req.proto_vers = htons(PPTP_VERSION); 215 ctl_req.framing_caps = htonl(PPTP_ASYNC_FRAMING); 216 ctl_req.bearer_caps = htonl(PPTP_ANALOG_ACCESS); 217 if ((err = pptp_send(fd, PPTP_START_CONTROL_CONNECTION_REQUEST, &ctl_req, sizeof(ctl_req), "start_control_connection_request"))) { 218 if (err == -2) 219 return -2; 220 return -1; 221 } 222 223 /* read the start reply */ 224 if ((err = pptp_recv(fd, PPTP_START_CONTROL_CONNECTION_REPLY, 225 &ctl_reply, sizeof(ctl_reply), "start_control_connection_reply"))) { 226 if (err == -2) 227 return -2; 228 if (err == -3) 229 return EXIT_PPTP_PROTOCOLERROR; 230 return -1; 231 } 232 if (ctl_reply.result_code != PPTP_RESULT_SUCCESS && ctl_reply.result_code != 0 /* radar 4395192 */) { 233 error("PPTP start_connection_control request failed, got result = %d, error = %d\n", ctl_reply.result_code, ctl_reply.error_code); 234 return EXIT_PPTP_PROTOCOLERROR; 235 } 236 237 /* send the outgoing call request */ 238 bzero(&out_req, sizeof(out_req)); 239 out_req.call_id = htons(ourcallid); 240 out_req.min_bps = htonl(0x12c); // ??? 241 out_req.max_bps = htonl(0x5f5e100); // ??? 242 out_req.bearer_type = htonl(PPTP_ANALOG_ACCESS + PPTP_DIGITAL_ACCESS); 243 out_req.framing_type = htonl(PPTP_ASYNC_FRAMING + PPTP_SYNC_FRAMING); 244 out_req.recv_window = htons(ourwindow); 245 out_req.processing_delay = htons(ourppd); 246 if ((err = pptp_send(fd, PPTP_OUTGOING_CALL_REQUEST, &out_req, sizeof(out_req), "outgoing_call_request"))) { 247 if (err == -2) 248 return -2; 249 return -1; 250 } 251 252 /* read the out reply */ 253 if ((err = pptp_recv(fd, PPTP_OUTGOING_CALL_REPLY, 254 &out_reply, sizeof(out_reply), "outgoing_call_reply"))) { 255 if (err == -2) 256 return -2; 257 if (err == -3) 258 return EXIT_PPTP_PROTOCOLERROR; 259 return -1; 260 } 261 if (out_reply.result_code != PPTP_OUTGOING_CALL_RESULT_CONNECTED) { 262 error("PPTP outgoing_call request failed, got result = %d, error = %d\n", out_reply.result_code, out_reply.error_code); 263 return EXIT_PPTP_PROTOCOLERROR; 264 } 265 266 /* call succedeed ! */ 267 *peercallid = ntohs(out_reply.call_id); 268 *peerwindow = ntohs(out_reply.recv_window); 269 *peerppd = ntohs(out_reply.processing_delay); 270 271 /* send set_link_info */ 272 bzero(&link_info, sizeof(link_info)); 273 link_info.peer_call_id = htons(*peercallid); 274 link_info.send_accm = htonl(0xFFFFFFFF); 275 link_info.recv_accm = htonl(0xFFFFFFFF); 276 if ((err = pptp_send(fd, PPTP_SET_LINK_INFO, &link_info, sizeof(link_info), "set_link_info_request"))) { 277 if (err == -2) 278 return -2; 279 return -1; 280 } 281 282 return 0; 283} 284 285/* ----------------------------------------------------------------------------- 286----------------------------------------------------------------------------- */ 287int pptp_incoming_call(int fd, 288 u_int16_t ourcallid, u_int16_t ourwindow, u_int16_t ourppd, 289 u_int16_t *peercallid, u_int16_t *peerwindow, u_int16_t *peerppd) 290{ 291 struct pptp_start_control_request ctl_req; 292 struct pptp_start_control_reply ctl_reply; 293 struct pptp_outgoing_call_request out_req; 294 struct pptp_outgoing_call_reply out_reply; 295 296 /* read the start request */ 297 if (pptp_recv(fd, PPTP_START_CONTROL_CONNECTION_REQUEST, 298 &ctl_req, sizeof(ctl_req), "start_control_connection_request")) { 299 return -1; 300 } 301 302 /* send the start control reply */ 303 bzero(&ctl_reply, sizeof(ctl_reply)); 304 ctl_reply.proto_vers = htons(PPTP_VERSION); 305 ctl_reply.result_code = PPTP_RESULT_SUCCESS; 306 ctl_reply.framing_caps = htonl(PPTP_ASYNC_FRAMING | PPTP_SYNC_FRAMING); 307 ctl_reply.bearer_caps = htonl(PPTP_ANALOG_ACCESS | PPTP_DIGITAL_ACCESS); 308 ctl_reply.max_channels = htons(1); 309 ctl_reply.firmware_rev = htons(1); 310 gethostname((char*)ctl_reply.hostname, 64); 311 strlcpy((char*)ctl_reply.vendor, PPTP_VENDOR, sizeof(ctl_reply.vendor)); 312 if (pptp_send(fd, PPTP_START_CONTROL_CONNECTION_REPLY, &ctl_reply, sizeof(ctl_reply), "start_control_connection_reply")) 313 return -1; 314 315 /* read the out request */ 316 if (pptp_recv(fd, PPTP_OUTGOING_CALL_REQUEST, 317 &out_req, sizeof(out_req), "outgoing_call_request")) { 318 return -1; 319 } 320 321 *peercallid = ntohs(out_req.call_id); 322 *peerwindow = ntohs(out_req.recv_window); 323 *peerppd = ntohs(out_req.processing_delay); 324 325 /* send the outgoing call reply */ 326 bzero(&out_reply, sizeof(out_reply)); 327 out_reply.call_id = htons(ourcallid); 328 out_reply.peer_call_id = htons(*peercallid); 329 out_reply.result_code = PPTP_OUTGOING_CALL_RESULT_CONNECTED; 330 // Already in network byte order 331 out_reply.connect_speed = out_req.max_bps; // ??? 332 out_reply.recv_window = htons(ourwindow); 333 out_reply.processing_delay = htons(ourppd); 334 if (pptp_send(fd, PPTP_OUTGOING_CALL_REPLY, &out_reply, sizeof(out_reply), "outgoing_call_reply")) { 335 return -1; 336 } 337 338 return 0; 339} 340 341/* ----------------------------------------------------------------------------- 342----------------------------------------------------------------------------- */ 343int pptp_echo(int fd, u_int32_t identifier) 344{ 345 struct pptp_echo_request echo_req; 346 int err; 347 348 /* send the echo request */ 349 echo_req.identifier = htonl(identifier); 350 if ((err = pptp_send(fd, PPTP_ECHO_REQUEST, &echo_req, sizeof(echo_req), "echo_request"))) { 351 if (err == -2) 352 return -2; 353 return -1; 354 } 355 356 return 0; 357} 358 359/* ----------------------------------------------------------------------------- 360----------------------------------------------------------------------------- */ 361int pptp_data_in(int fd) 362{ 363 struct pptp_header header; 364 struct pptp_echo_request echo_req; 365 struct pptp_echo_reply echo_reply; 366 struct pptp_set_link_info info_req; 367 int err; 368 369 if ((err = readn(fd, &header, sizeof(header))) != sizeof(header)) { 370 error("PPTP error when reading header : read %d, expected %d bytes\n", err, sizeof(header)); 371 return -1; 372 } 373 374 switch (ntohs(header.ctrl_msgtype)) { 375 case PPTP_ECHO_REQUEST: 376 // read the identifier 377 if ((err = readn(fd, &echo_req, sizeof(echo_req))) != sizeof(echo_req)) { 378 error("PPTP error when reading echo request : read %d, expected %d bytes\n", err, sizeof(echo_req)); 379 return -1; 380 } 381 bzero(&echo_reply, sizeof(echo_reply)); 382 // Already in network byte order 383 echo_reply.identifier = echo_req.identifier; 384 echo_reply.result_code = PPTP_RESULT_SUCCESS; 385 if (pptp_send(fd, PPTP_ECHO_REPLY, &echo_reply, sizeof(echo_reply), "echo_reply")) { 386 return -1; 387 } 388 break; 389 390 case PPTP_ECHO_REPLY: 391 // read the identifier 392 if ((err = readn(fd, &echo_reply, sizeof(echo_reply))) != sizeof(echo_reply)) { 393 error("PPTP error when reading echo echo_reply : read %d, expected %d bytes\n", err, sizeof(echo_reply)); 394 return -1; 395 } 396 pptp_received_echo_reply(ntohl(echo_reply.identifier), echo_reply.result_code, echo_reply.error_code); 397 break; 398 399 case PPTP_SET_LINK_INFO: 400 // ignore 401 if ((err = readn(fd, &info_req, sizeof(info_req))) != sizeof(info_req)) { 402 error("PPTP error when reading set_info_link request : read %d, expected %d bytes\n", err, sizeof(info_req)); 403 return -1; 404 } 405 break; 406 407 case PPTP_START_CONTROL_CONNECTION_REQUEST: 408 case PPTP_START_CONTROL_CONNECTION_REPLY: 409 case PPTP_STOP_CONTROL_CONNECTION_REQUEST: 410 case PPTP_STOP_CONTROL_CONNECTION_REPLY: 411 case PPTP_OUTGOING_CALL_REQUEST: 412 case PPTP_OUTGOING_CALL_REPLY: 413 case PPTP_INCOMING_CALL_REQUEST: 414 case PPTP_INCOMING_CALL_REPLY: 415 case PPTP_INCOMING_CALL_CONNECTED: 416 case PPTP_CALL_CLEAR_REQUEST: 417 case PPTP_CALL_DISCONNECT_NOTIFY: 418 case PPTP_WAN_ERROR_NOTIFY: 419 dbglog("PPTP received %s message\n", control_msgs[ntohs(header.ctrl_msgtype)]); 420 break; 421 422 default: 423 if (header.ctrl_msgtype) 424 error("PPTP received unexpected message type = %d\n", ntohs(header.ctrl_msgtype)); 425 //return -1; // do we disconnect ??? 426 } 427 428 return 0; 429} 430 431