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