1/* pptp_ctrl.c ... handle PPTP control connection.
2 *                 C. Scott Ananian <cananian@alumni.princeton.edu>
3 *
4 * $Id: pptp_ctrl.c,v 1.31 2005/03/31 07:42:39 quozl Exp $
5 */
6
7#include <errno.h>
8#include <sys/time.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <netinet/in.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <assert.h>
15#include <signal.h>
16#include <string.h>
17#include <ctype.h>
18#include <fcntl.h>
19#include "pptp_msg.h"
20#include "pptp_ctrl.h"
21#include "pptp_options.h"
22#include "vector.h"
23#include "util.h"
24#include "pptp_quirks.h"
25
26/* BECAUSE OF SIGNAL LIMITATIONS, EACH PROCESS CAN ONLY MANAGE ONE
27 * CONNECTION.  SO THIS 'PPTP_CONN' STRUCTURE IS A BIT MISLEADING.
28 * WE'LL KEEP CONNECTION-SPECIFIC INFORMATION IN THERE ANYWAY (AS
29 * OPPOSED TO USING GLOBAL VARIABLES), BUT BEWARE THAT THE ENTIRE
30 * UNIX SIGNAL-HANDLING SEMANTICS WOULD HAVE TO CHANGE (OR THE
31 * TIME-OUT CODE DRASTICALLY REWRITTEN) BEFORE YOU COULD DO A
32 * PPTP_CONN_OPEN MORE THAN ONCE PER PROCESS AND GET AWAY WITH IT.
33 */
34
35/* This structure contains connection-specific information that the
36 * signal handler needs to see.  Thus, it needs to be in a global
37 * variable.  If you end up using pthreads or something (why not
38 * just processes?), this would have to be placed in a thread-specific
39 * data area, using pthread_get|set_specific, etc., so I've
40 * conveniently encapsulated it for you.
41 * [linux threads will have to support thread-specific signals
42 *  before this would work at all, which, as of this writing
43 *  (linux-threads v0.6, linux kernel 2.1.72), it does not.]
44 */
45
46/* Globals */
47
48/* control the number of times echo packets will be logged */
49static int nlogecho = 10;
50
51static struct thread_specific {
52    struct sigaction old_sigaction; /* evil signals */
53    PPTP_CONN * conn;
54} global;
55
56#define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */
57
58struct PPTP_CONN {
59    int inet_sock;
60    /* Connection States */
61    enum {
62        CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED
63    } conn_state; /* on startup: CONN_IDLE */
64    /* Keep-alive states */
65    enum {
66        KA_NONE, KA_OUTSTANDING
67    } ka_state;  /* on startup: KA_NONE */
68    /* Keep-alive ID; monotonically increasing (watch wrap-around!) */
69    u_int32_t ka_id; /* on startup: 1 */
70    /* Other properties. */
71    u_int16_t version;
72    u_int16_t firmware_rev;
73    u_int8_t  hostname[64], vendor[64];
74    /* XXX these are only PNS properties, currently XXX */
75    /* Call assignment information. */
76    u_int16_t call_serial_number;
77    VECTOR *call;
78    void * closure;
79    pptp_conn_cb callback;
80    /******* IO buffers ******/
81    char * read_buffer, *write_buffer;
82    size_t read_alloc,   write_alloc;
83    size_t read_size,    write_size;
84};
85
86struct PPTP_CALL {
87    /* Call properties */
88    enum {
89        PPTP_CALL_PAC, PPTP_CALL_PNS
90    } call_type;
91    union {
92        enum pptp_pac_state {
93            PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS
94        } pac;
95        enum pptp_pns_state {
96            PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT
97        } pns;
98    } state;
99    u_int16_t call_id, peer_call_id;
100    u_int16_t sernum;
101    u_int32_t speed;
102    /* For user data: */
103    pptp_call_cb callback;
104    void * closure;
105};
106
107
108/* PPTP error codes: ----------------------------------------------*/
109
110/* (General Error Codes) */
111static const struct {
112    const char *name, *desc;
113} pptp_general_errors[] = {
114#define PPTP_GENERAL_ERROR_NONE                 0
115    { "(None)", "No general error" },
116#define PPTP_GENERAL_ERROR_NOT_CONNECTED        1
117    { "(Not-Connected)", "No control connection exists yet for this "
118        "PAC-PNS pair" },
119#define PPTP_GENERAL_ERROR_BAD_FORMAT           2
120    { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" },
121#define PPTP_GENERAL_ERROR_BAD_VALUE            3
122    { "(Bad-Value)", "One of the field values was out of range or "
123            "reserved field was non-zero" },
124#define PPTP_GENERAL_ERROR_NO_RESOURCE          4
125    { "(No-Resource)", "Insufficient resources to handle this command now" },
126#define PPTP_GENERAL_ERROR_BAD_CALLID           5
127    { "(Bad-Call ID)", "The Call ID is invalid in this context" },
128#define PPTP_GENERAL_ERROR_PAC_ERROR            6
129    { "(PAC-Error)", "A generic vendor-specific error occured in the PAC" }
130};
131
132#define  MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \
133        sizeof(pptp_general_errors[0]) - 1)
134
135/* Outgoing Call Reply Result Codes */
136static const char *pptp_out_call_reply_result[] = {
137/* 0 */	"Unknown Result Code",
138/* 1 */	"Connected",
139/* 2 */	"General Error",
140/* 3 */	"No Carrier Detected",
141/* 4 */	"Busy Signal",
142/* 5 */	"No Dial Tone",
143/* 6 */	"Time Out",
144/* 7 */	"Not Accepted, Call is administratively prohibited" };
145
146#define MAX_OUT_CALL_REPLY_RESULT 7
147
148/* Call Disconnect Notify  Result Codes */
149static const char *pptp_call_disc_ntfy[] = {
150/* 0 */	"Unknown Result Code",
151/* 1 */	"Lost Carrier",
152/* 2 */	"General Error",
153/* 3 */	"Administrative Shutdown",
154/* 4 */	"(your) Request" };
155
156#define MAX_CALL_DISC_NTFY 4
157
158/* Call Disconnect Notify  Result Codes */
159static const char *pptp_start_ctrl_conn_rply[] = {
160/* 0 */	"Unknown Result Code",
161/* 1 */	"Successful Channel Establishment",
162/* 2 */	"General Error",
163/* 3 */	"Command Channel Already Exists",
164/* 4 */	"Requester is not Authorized" };
165
166#define MAX_START_CTRL_CONN_REPLY 4
167
168/* timing options */
169int idle_wait = PPTP_TIMEOUT;
170int max_echo_wait = PPTP_TIMEOUT;
171
172/* Local prototypes */
173static void pptp_reset_timer(void);
174static void pptp_handle_timer();
175/* Write/read as much as we can without blocking. */
176int pptp_write_some(PPTP_CONN * conn);
177int pptp_read_some(PPTP_CONN * conn);
178/* Make valid packets from read_buffer */
179int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size);
180/* Add packet to write_buffer */
181int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size);
182/* Dispatch packets (general) */
183int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size);
184/* Dispatch packets (control messages) */
185int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size);
186/* Set link info, for pptp servers that need it.
187   this is a noop, unless the user specified a quirk and
188   there's a set_link hook defined in the quirks table
189   for that quirk */
190void pptp_set_link(PPTP_CONN * conn, int peer_call_id);
191
192/*** log error information in control packets *********************************/
193static void ctrlp_error( int result, int error, int cause,
194        const char *result_text[], int max_result)
195{
196    if( cause >= 0)
197        log("Result code is %d '%s'. Error code is %d, Cause code is %d",
198                result, result_text[result <= max_result ?  result : 0], error,
199                cause );
200    else
201        log("Reply result code is %d '%s'. Error code is %d",
202                result, result_text[result <= max_result ?  result : 0], error);
203    if ((error > 0) && (error <= MAX_GENERAL_ERROR)){
204        if( result != PPTP_RESULT_GENERAL_ERROR )
205            log("Result code is something else then \"general error\", "
206                    "so the following error is probably bogus.");
207        log("Error is '%s', Error message: '%s'",
208                pptp_general_errors[error].name,
209                pptp_general_errors[error].desc);
210    }
211}
212
213#ifdef nostrip //Modified by Silver to shrink code  //Winster Chan added 05/16/2006
214static const char *ctrl_msg_types[] = {
215         "invalid control message type",
216/*         (Control Connection Management) */
217         "Start-Control-Connection-Request",            /* 1 */
218         "Start-Control-Connection-Reply",              /* 2 */
219         "Stop-Control-Connection-Request",             /* 3 */
220         "Stop-Control-Connection-Reply",               /* 4 */
221         "Echo-Request",                                /* 5 */
222         "Echo-Reply",                                  /* 6 */
223/*         (Call Management) */
224         "Outgoing-Call-Request",                       /* 7 */
225         "Outgoing-Call-Reply",                         /* 8 */
226         "Incoming-Call-Request",                       /* 9 */
227         "Incoming-Call-Reply",                        /* 10 */
228         "Incoming-Call-Connected",                    /* 11 */
229         "Call-Clear-Request",                         /* 12 */
230         "Call-Disconnect-Notify",                     /* 13 */
231/*         (Error Reporting) */
232         "WAN-Error-Notify",                           /* 14 */
233/*         (PPP Session Control) */
234         "Set-Link-Info"                              /* 15 */
235};
236#define MAX_CTRLMSG_TYPE 15
237#endif  //Winster Chan added 05/16/2006
238
239/*** report a sent packet ****************************************************/
240static void ctrlp_rep( void * buffer, int size, int isbuff)
241{
242    struct pptp_header *packet = buffer;
243    unsigned int type;
244    if(size < sizeof(struct pptp_header)) return;
245    type = ntoh16(packet->ctrl_type);
246    /* FIXME: do not report sending echo requests as long as they are
247     * sent in a signal handler. This may dead lock as the syslog call
248     * is not reentrant */
249    if( type ==  PPTP_ECHO_RQST ) return;
250    /* don't keep reporting sending of echo's */
251    if( (type == PPTP_ECHO_RQST || type == PPTP_ECHO_RPLY) && nlogecho <= 0 ) return;
252    log("%s control packet type is %d '%s'\n",isbuff ? "Buffered" : "Sent",
253            type, ctrl_msg_types[type <= MAX_CTRLMSG_TYPE ? type : 0]);
254
255}
256
257
258
259/* Open new pptp_connection.  Returns NULL on failure. */
260PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
261{
262    PPTP_CONN *conn;
263    /* Allocate structure */
264    if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
265    if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
266    /* Initialize */
267    conn->inet_sock = inet_sock;
268    conn->conn_state = CONN_IDLE;
269    conn->ka_state  = KA_NONE;
270    conn->ka_id     = 1;
271    conn->call_serial_number = 0;
272    conn->callback  = callback;
273    /* Create I/O buffers */
274    conn->read_size = conn->write_size = 0;
275    conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE;
276    conn->read_buffer =
277        malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc);
278    conn->write_buffer =
279        malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc);
280    if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
281        if (conn->read_buffer  != NULL) free(conn->read_buffer);
282        if (conn->write_buffer != NULL) free(conn->write_buffer);
283        vector_destroy(conn->call); free(conn); return NULL;
284    }
285    /* Make this socket non-blocking. */
286    fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
287    /* Request connection from server, if this is a client */
288    if (isclient) {
289        struct pptp_start_ctrl_conn packet = {
290            PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
291            hton16(PPTP_VERSION), 0, 0,
292            hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
293            hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
294            PPTP_HOSTNAME, PPTP_VENDOR
295        };
296        /* fix this packet, if necessary */
297        int idx, rc;
298        idx = get_quirk_index();
299        if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
300            if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
301                warn("calling the start_ctrl_conn hook failed (%d)", rc);
302        }
303        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
304            conn->conn_state = CONN_WAIT_CTL_REPLY;
305        else
306            return NULL; /* could not send initial start request. */
307    }
308    /* Set up interval/keep-alive timer */
309    /*   First, register handler for SIGALRM */
310    sigpipe_create();
311    sigpipe_assign(SIGALRM);
312    global.conn = conn;
313    /* Reset event timer */
314    pptp_reset_timer();
315    /* all done. */
316    return conn;
317}
318
319int pptp_conn_established(PPTP_CONN *conn) {
320  return (conn->conn_state == CONN_ESTABLISHED);
321}
322
323/* This currently *only* works for client call requests.
324 * We need to do something else to allocate calls for incoming requests.
325 */
326PPTP_CALL * pptp_call_open(PPTP_CONN * conn, pptp_call_cb callback,
327        char *phonenr)
328{
329    PPTP_CALL * call;
330    int i;
331    int idx, rc;
332    /* Send off the call request */
333    struct pptp_out_call_rqst packet = {
334        PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
335        0,0, /*call_id, sernum */
336        hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
337        hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP),
338        hton16(PPTP_WINDOW), 0, 0, 0, {0}, {0}
339    };
340    assert(conn && conn->call);
341    assert(conn->conn_state == CONN_ESTABLISHED);
342    /* Assign call id */
343    if (!vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &i))
344        /* no more calls available! */
345        return NULL;
346    /* allocate structure. */
347    if ((call = malloc(sizeof(*call))) == NULL) return NULL;
348    /* Initialize call structure */
349    call->call_type = PPTP_CALL_PNS;
350    call->state.pns = PNS_IDLE;
351    call->call_id   = (u_int16_t) i;
352    call->sernum    = conn->call_serial_number++;
353    call->callback  = callback;
354    call->closure   = NULL;
355    packet.call_id = htons(call->call_id);
356    packet.call_sernum = htons(call->sernum);
357    /* if we have a quirk, build a new packet to fit it */
358    idx = get_quirk_index();
359    if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) {
360        if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet)))
361            warn("calling the out_call_rqst hook failed (%d)", rc);
362    }
363    /* fill in the phone number if it was specified */
364    if (phonenr) {
365        strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num));
366        packet.phone_len = strlen(phonenr);
367        if( packet.phone_len > sizeof(packet.phone_num))
368            packet.phone_len = sizeof(packet.phone_num);
369        packet.phone_len = hton16 (packet.phone_len);
370    }
371    if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
372        pptp_reset_timer();
373        call->state.pns = PNS_WAIT_REPLY;
374        /* and add it to the call vector */
375        vector_insert(conn->call, i, call);
376        return call;
377    } else { /* oops, unsuccessful. Deallocate. */
378        free(call);
379        return NULL;
380    }
381}
382
383/*** pptp_call_close **********************************************************/
384void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call)
385{
386    struct pptp_call_clear_rqst rqst = {
387        PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0
388    };
389    assert(conn && conn->call); assert(call);
390    assert(vector_contains(conn->call, call->call_id));
391    /* haven't thought about PAC yet */
392    assert(call->call_type == PPTP_CALL_PNS);
393    assert(call->state.pns != PNS_IDLE);
394    rqst.call_id = hton16(call->call_id);
395    /* don't check state against WAIT_DISCONNECT... allow multiple disconnect
396     * requests to be made.
397     */
398    pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
399    pptp_reset_timer();
400    call->state.pns = PNS_WAIT_DISCONNECT;
401    /* call structure will be freed when we have confirmation of disconnect. */
402}
403
404/*** hard close ***************************************************************/
405void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call)
406{
407    assert(conn && conn->call); assert(call);
408    assert(vector_contains(conn->call, call->call_id));
409    /* notify */
410    if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE);
411    /* deallocate */
412    vector_remove(conn->call, call->call_id);
413    free(call);
414}
415
416/*** this is a soft close *****************************************************/
417void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason)
418{
419    struct pptp_stop_ctrl_conn rqst = {
420        PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST),
421        hton8(close_reason), 0, 0
422    };
423    int i;
424    assert(conn && conn->call);
425    /* avoid repeated close attempts */
426    if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY)
427        return;
428    /* close open calls, if any */
429    for (i = 0; i < vector_size(conn->call); i++)
430        pptp_call_close(conn, vector_get_Nth(conn->call, i));
431    /* now close connection */
432    log("Closing PPTP connection");
433    pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
434    pptp_reset_timer(); /* wait 60 seconds for reply */
435    conn->conn_state = CONN_WAIT_STOP_REPLY;
436    return;
437}
438
439/*** this is a hard close *****************************************************/
440void pptp_conn_destroy(PPTP_CONN * conn)
441{
442    int i;
443    assert(conn != NULL); assert(conn->call != NULL);
444    /* destroy all open calls */
445    for (i = 0; i < vector_size(conn->call); i++)
446        pptp_call_destroy(conn, vector_get_Nth(conn->call, i));
447    /* notify */
448    if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE);
449    sigpipe_close();
450    close(conn->inet_sock);
451    /* deallocate */
452    vector_destroy(conn->call);
453    free(conn);
454}
455
456/*** Deal with messages, in a non-blocking manner
457 * Add file descriptors used by pptp to fd_set.
458 */
459void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set,
460                 int * max_fd)
461{
462    assert(conn && conn->call);
463    /* Add fd to write_set if there are outstanding writes. */
464    if (conn->write_size > 0)
465        FD_SET(conn->inet_sock, write_set);
466    /* Always add fd to read_set. (always want something to read) */
467    FD_SET(conn->inet_sock, read_set);
468    if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock;
469    /* Add signal pipe file descriptor to set */
470    int sig_fd = sigpipe_fd();
471    FD_SET(sig_fd, read_set);
472    if (*max_fd < sig_fd) *max_fd = sig_fd;
473}
474
475/*** handle any pptp file descriptors set in fd_set, and clear them ***********/
476int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set)
477{
478    int r = 0;
479    assert(conn && conn->call);
480    /* Check for signals */
481    if (FD_ISSET(sigpipe_fd(), read_set)) {
482        if (sigpipe_read() == SIGALRM) pptp_handle_timer();
483	FD_CLR(sigpipe_fd(), read_set);
484    }
485    /* Check write_set could be set. */
486    if (FD_ISSET(conn->inet_sock, write_set)) {
487        FD_CLR(conn->inet_sock, write_set);
488        if (conn->write_size > 0)
489            r = pptp_write_some(conn);/* write as much as we can without blocking */
490    }
491    /* Check read_set */
492    if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) {
493        void *buffer; size_t size;
494        FD_CLR(conn->inet_sock, read_set);
495        r = pptp_read_some(conn); /* read as much as we can without blocking */
496	if (r < 0)
497	    return r;
498        /* make packets of the buffer, while we can. */
499        while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) {
500            r = pptp_dispatch_packet(conn, buffer, size);
501            free(buffer);
502        }
503    }
504    /* That's all, folks.  Simple, eh? */
505    return r;
506}
507
508/*** Non-blocking write *******************************************************/
509int pptp_write_some(PPTP_CONN * conn) {
510    ssize_t retval;
511    assert(conn && conn->call);
512    retval = write(conn->inet_sock, conn->write_buffer, conn->write_size);
513    if (retval < 0) { /* error. */
514        if (errno == EAGAIN || errno == EINTR) {
515            return 0;
516        } else { /* a real error */
517            log("write error: %s", strerror(errno));
518	    return -1;
519        }
520    }
521    assert(retval <= conn->write_size);
522    conn->write_size -= retval;
523    memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size);
524    ctrlp_rep(conn->write_buffer, retval, 0);
525    return 0;
526}
527
528/*** Non-blocking read ********************************************************/
529int pptp_read_some(PPTP_CONN * conn)
530{
531    ssize_t retval;
532    assert(conn && conn->call);
533    if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */
534        char *new_buffer = realloc(conn->read_buffer,
535                sizeof(*(conn->read_buffer)) * conn->read_alloc * 2);
536        if (new_buffer == NULL) {
537            log("Out of memory"); return -1;
538        }
539        conn->read_alloc *= 2;
540        conn->read_buffer = new_buffer;
541    }
542    retval = read(conn->inet_sock, conn->read_buffer + conn->read_size,
543            conn->read_alloc  - conn->read_size);
544    if (retval == 0) {
545        log("read returned zero, peer has closed");
546        return -1;
547    }
548    if (retval < 0) {
549        if (errno == EINTR || errno == EAGAIN)
550	    return 0;
551        else { /* a real error */
552            log("read error: %s", strerror(errno));
553            return -1;
554        }
555    }
556    conn->read_size += retval;
557    assert(conn->read_size <= conn->read_alloc);
558    return 0;
559}
560
561/*** Packet formation *********************************************************/
562int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size)
563{
564    struct pptp_header *header;
565    size_t bad_bytes = 0;
566    assert(conn && conn->call); assert(buf != NULL); assert(size != NULL);
567    /* Give up unless there are at least sizeof(pptp_header) bytes */
568    while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) {
569        /* Throw out bytes until we have a valid header. */
570        header = (struct pptp_header *) (conn->read_buffer + bad_bytes);
571        if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout;
572        if (ntoh16(header->reserved0) != 0)
573            log("reserved0 field is not zero! (0x%x) Cisco feature? \n",
574                    ntoh16(header->reserved0));
575        if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout;
576        if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout;
577        /* well.  I guess it's good. Let's see if we've got it all. */
578        if (ntoh16(header->length) > (conn->read_size-bad_bytes))
579            /* nope.  Let's wait until we've got it, then. */
580            goto flushbadbytes;
581        /* One last check: */
582        if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) &&
583                (ntoh16(header->length) !=
584                         PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))))
585            goto throwitout;
586        /* well, I guess we've got it. */
587        *size = ntoh16(header->length);
588        *buf = malloc(*size);
589        if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ }
590        memcpy(*buf, conn->read_buffer + bad_bytes, *size);
591        /* Delete this packet from the read_buffer. */
592        conn->read_size -= (bad_bytes + *size);
593        memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size,
594                conn->read_size);
595        if (bad_bytes > 0)
596            log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
597        return 1;
598throwitout:
599        bad_bytes++;
600    }
601flushbadbytes:
602    /* no more packets.  Let's get rid of those bad bytes */
603    conn->read_size -= bad_bytes;
604    memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size);
605    if (bad_bytes > 0)
606        log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
607    return 0;
608}
609
610/*** pptp_send_ctrl_packet ****************************************************/
611int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size)
612{
613    assert(conn && conn->call); assert(buffer);
614    if( conn->write_size > 0) pptp_write_some( conn);
615    if( conn->write_size == 0) {
616        ssize_t retval;
617        retval = write(conn->inet_sock, buffer, size);
618        if (retval < 0) { /* error. */
619            if (errno == EAGAIN || errno == EINTR) {
620                /* ignore */;
621                retval = 0;
622            } else { /* a real error */
623                log("write error: %s", strerror(errno));
624                pptp_conn_destroy(conn); /* shut down fast. */
625                return 0;
626            }
627        }
628        ctrlp_rep( buffer, retval, 0);
629        size -= retval;
630        if( size <= 0) return 1;
631    }
632    /* Shove anything not written into the write buffer */
633    if (conn->write_size + size > conn->write_alloc) { /* need more memory */
634        char *new_buffer = realloc(conn->write_buffer,
635                sizeof(*(conn->write_buffer)) * conn->write_alloc * 2);
636        if (new_buffer == NULL) {
637            log("Out of memory"); return 0;
638        }
639        conn->write_alloc *= 2;
640        conn->write_buffer = new_buffer;
641    }
642    memcpy(conn->write_buffer + conn->write_size, buffer, size);
643    conn->write_size += size;
644    ctrlp_rep( buffer,size,1);
645    return 1;
646}
647
648/*** Packet Dispatch **********************************************************/
649int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size)
650{
651    int r = 0;
652    struct pptp_header *header = (struct pptp_header *)buffer;
653    assert(conn && conn->call); assert(buffer);
654    assert(ntoh32(header->magic) == PPTP_MAGIC);
655    assert(ntoh16(header->length) == size);
656    switch (ntoh16(header->pptp_type)) {
657        case PPTP_MESSAGE_CONTROL:
658            r = ctrlp_disp(conn, buffer, size);
659            break;
660        case PPTP_MESSAGE_MANAGE:
661            /* MANAGEMENT messages aren't even part of the spec right now. */
662            log("PPTP management message received, but not understood.");
663            break;
664        default:
665            log("Unknown PPTP control message type received: %u",
666                    (unsigned int) ntoh16(header->pptp_type));
667            break;
668    }
669    return r;
670}
671
672/*** log echo request/replies *************************************************/
673static void logecho( int type)
674{
675    /* hack to stop flooding the log files (the most interesting part is right
676     * after the connection built-up) */
677    if( nlogecho > 0) {
678        log( "Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply");
679        if( --nlogecho == 0)
680            log("no more Echo Reply/Request packets will be reported.");
681    }
682}
683
684/*** pptp_dispatch_ctrl_packet ************************************************/
685int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size)
686{
687    struct pptp_header *header = (struct pptp_header *)buffer;
688    u_int8_t close_reason = PPTP_STOP_NONE;
689    assert(conn && conn->call); assert(buffer);
690    assert(ntoh32(header->magic) == PPTP_MAGIC);
691    assert(ntoh16(header->length) == size);
692    assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL);
693    if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) {
694        log("Invalid packet received [type: %d; length: %d].",
695                (int) ntoh16(header->ctrl_type), (int) size);
696        return 0;
697    }
698    switch (ntoh16(header->ctrl_type)) {
699        /* ----------- STANDARD Start-Session MESSAGES ------------ */
700        case PPTP_START_CTRL_CONN_RQST:
701        {
702            struct pptp_start_ctrl_conn *packet =
703                (struct pptp_start_ctrl_conn *) buffer;
704            struct pptp_start_ctrl_conn reply = {
705                PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
706                hton16(PPTP_VERSION), 0, 0,
707                hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
708                hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
709                PPTP_HOSTNAME, PPTP_VENDOR };
710            int idx, rc;
711            log("Received Start Control Connection Request");
712            /* fix this packet, if necessary */
713            idx = get_quirk_index();
714            if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
715                if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply)))
716                    warn("calling the start_ctrl_conn hook failed (%d)", rc);
717            }
718            if (conn->conn_state == CONN_IDLE) {
719                if (ntoh16(packet->version) < PPTP_VERSION) {
720                    /* Can't support this (earlier) PPTP_VERSION */
721                    reply.version = packet->version;
722                    /* protocol version not supported */
723                    reply.result_code = hton8(5);
724                    pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
725                    pptp_reset_timer(); /* give sender a chance for a retry */
726                } else { /* same or greater version */
727                    if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
728                        conn->conn_state = CONN_ESTABLISHED;
729                        log("server connection ESTABLISHED.");
730                        pptp_reset_timer();
731                    }
732                }
733            }
734            break;
735        }
736        case PPTP_START_CTRL_CONN_RPLY:
737        {
738            struct pptp_start_ctrl_conn *packet =
739                (struct pptp_start_ctrl_conn *) buffer;
740            log("Received Start Control Connection Reply");
741            if (conn->conn_state == CONN_WAIT_CTL_REPLY) {
742                /* XXX handle collision XXX [see rfc] */
743                if (ntoh16(packet->version) != PPTP_VERSION) {
744                    if (conn->callback != NULL)
745                        conn->callback(conn, CONN_OPEN_FAIL);
746                    close_reason = PPTP_STOP_PROTOCOL;
747                    goto pptp_conn_close;
748                }
749                if (ntoh8(packet->result_code) != 1 &&
750                    /* J'ai change le if () afin que la connection ne se ferme
751                     * pas pour un "rien" :p adel@cybercable.fr -
752                     *
753                     * Don't close the connection if the result code is zero
754                     * (feature found in certain ADSL modems)
755                     */
756                        ntoh8(packet->result_code) != 0) {
757                    log("Negative reply received to our Start Control "
758                            "Connection Request");
759                    ctrlp_error(packet->result_code, packet->error_code,
760                            -1, pptp_start_ctrl_conn_rply,
761                            MAX_START_CTRL_CONN_REPLY);
762                    if (conn->callback != NULL)
763                        conn->callback(conn, CONN_OPEN_FAIL);
764                    close_reason = PPTP_STOP_PROTOCOL;
765                    goto pptp_conn_close;
766                }
767                conn->conn_state = CONN_ESTABLISHED;
768                /* log session properties */
769                conn->version      = ntoh16(packet->version);
770                conn->firmware_rev = ntoh16(packet->firmware_rev);
771                memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname));
772                memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor));
773                pptp_reset_timer(); /* 60 seconds until keep-alive */
774                log("Client connection established.");
775                if (conn->callback != NULL)
776                    conn->callback(conn, CONN_OPEN_DONE);
777            } /* else goto pptp_conn_close; */
778            break;
779        }
780            /* ----------- STANDARD Stop-Session MESSAGES ------------ */
781        case PPTP_STOP_CTRL_CONN_RQST:
782        {
783            /* conn_state should be CONN_ESTABLISHED, but it could be
784             * something else */
785            struct pptp_stop_ctrl_conn reply = {
786                PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY),
787                hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
788            };
789            log("Received Stop Control Connection Request.");
790            if (conn->conn_state == CONN_IDLE) break;
791            if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
792                if (conn->callback != NULL)
793                    conn->callback(conn, CONN_CLOSE_RQST);
794                conn->conn_state = CONN_IDLE;
795		return -1;
796            }
797            break;
798        }
799        case PPTP_STOP_CTRL_CONN_RPLY:
800        {
801            log("Received Stop Control Connection Reply.");
802            /* conn_state should be CONN_WAIT_STOP_REPLY, but it
803             * could be something else */
804            if (conn->conn_state == CONN_IDLE) break;
805            conn->conn_state = CONN_IDLE;
806	    return -1;
807        }
808            /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */
809        case PPTP_ECHO_RPLY:
810        {
811            struct pptp_echo_rply *packet =
812                (struct pptp_echo_rply *) buffer;
813            logecho( PPTP_ECHO_RPLY);
814            if ((conn->ka_state == KA_OUTSTANDING) &&
815                    (ntoh32(packet->identifier) == conn->ka_id)) {
816                conn->ka_id++;
817                conn->ka_state = KA_NONE;
818                pptp_reset_timer();
819            }
820            break;
821        }
822        case PPTP_ECHO_RQST:
823        {
824            struct pptp_echo_rqst *packet =
825                (struct pptp_echo_rqst *) buffer;
826            struct pptp_echo_rply reply = {
827                PPTP_HEADER_CTRL(PPTP_ECHO_RPLY),
828                packet->identifier, /* skip hton32(ntoh32(id)) */
829                hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
830            };
831            logecho( PPTP_ECHO_RQST);
832            pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
833            pptp_reset_timer();
834            break;
835        }
836            /* ----------- OUTGOING CALL MESSAGES ------------ */
837        case PPTP_OUT_CALL_RQST:
838        {
839            struct pptp_out_call_rqst *packet =
840                (struct pptp_out_call_rqst *)buffer;
841            struct pptp_out_call_rply reply = {
842                PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
843                0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0,
844                hton32(PPTP_CONNECT_SPEED),
845                hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0
846            };
847            log("Received Outgoing Call Request.");
848            /* XXX PAC: eventually this should make an outgoing call. XXX */
849            reply.result_code = hton8(7); /* outgoing calls verboten */
850            pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
851            break;
852        }
853        case PPTP_OUT_CALL_RPLY:
854        {
855            struct pptp_out_call_rply *packet =
856                (struct pptp_out_call_rply *)buffer;
857            PPTP_CALL * call;
858            u_int16_t callid = ntoh16(packet->call_id_peer);
859            log("Received Outgoing Call Reply.");
860            if (!vector_search(conn->call, (int) callid, &call)) {
861                log("PPTP_OUT_CALL_RPLY received for non-existant call: "
862                        "peer call ID (us)  %d call ID (them) %d.",
863                        callid, ntoh16(packet->call_id));
864                break;
865            }
866            if (call->call_type != PPTP_CALL_PNS) {
867                log("Ack!  How did this call_type get here?"); /* XXX? */
868                break;
869            }
870            if (call->state.pns != PNS_WAIT_REPLY) {
871                warn("Unexpected(?) Outgoing Call Reply will be ignored.");
872                break;
873            }
874            /* check for errors */
875            if (packet->result_code != 1) {
876                /* An error.  Log it verbosely. */
877                log("Our outgoing call request [callid %d] has not been "
878                        "accepted.", (int) callid);
879                ctrlp_error(packet->result_code, packet->error_code,
880                        packet->cause_code, pptp_out_call_reply_result,
881                        MAX_OUT_CALL_REPLY_RESULT);
882                call->state.pns = PNS_IDLE;
883                if (call->callback != NULL)
884                    call->callback(conn, call, CALL_OPEN_FAIL);
885                pptp_call_destroy(conn, call);
886            } else {
887                /* connection established */
888                call->state.pns = PNS_ESTABLISHED;
889                call->peer_call_id = ntoh16(packet->call_id);
890                call->speed        = ntoh32(packet->speed);
891                pptp_reset_timer();
892                /* call pptp_set_link. unless the user specified a quirk
893                   and this quirk has a set_link hook, this is a noop */
894                pptp_set_link(conn, call->peer_call_id);
895                if (call->callback != NULL)
896                    call->callback(conn, call, CALL_OPEN_DONE);
897                log("Outgoing call established (call ID %u, peer's "
898                        "call ID %u).\n", call->call_id, call->peer_call_id);
899            }
900            break;
901        }
902            /* ----------- INCOMING CALL MESSAGES ------------ */
903            /* XXX write me XXX */
904            /* ----------- CALL CONTROL MESSAGES ------------ */
905        case PPTP_CALL_CLEAR_RQST:
906        {
907            struct pptp_call_clear_rqst *packet =
908                (struct pptp_call_clear_rqst *)buffer;
909            struct pptp_call_clear_ntfy reply = {
910                PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id,
911                1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0}
912            };
913            log("Received Call Clear Request.");
914            if (vector_contains(conn->call, ntoh16(packet->call_id))) {
915                PPTP_CALL * call;
916                vector_search(conn->call, ntoh16(packet->call_id), &call);
917                if (call->callback != NULL)
918                    call->callback(conn, call, CALL_CLOSE_RQST);
919                pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
920                pptp_call_destroy(conn, call);
921                log("Call closed (RQST) (call id %d)", (int) call->call_id);
922            }
923            break;
924        }
925        case PPTP_CALL_CLEAR_NTFY:
926        {
927            struct pptp_call_clear_ntfy *packet =
928                (struct pptp_call_clear_ntfy *)buffer;
929            log("Call disconnect notification received (call id %d)",
930                    ntoh16(packet->call_id));
931            if (vector_contains(conn->call, ntoh16(packet->call_id))) {
932                PPTP_CALL * call;
933                ctrlp_error(packet->result_code, packet->error_code,
934                        packet->cause_code, pptp_call_disc_ntfy,
935                        MAX_CALL_DISC_NTFY);
936                vector_search(conn->call, ntoh16(packet->call_id), &call);
937                pptp_call_destroy(conn, call);
938            }
939            /* XXX we could log call stats here XXX */
940            /* XXX not all servers send this XXX */
941            break;
942        }
943        case PPTP_SET_LINK_INFO:
944        {
945            /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */
946            /* this is really dealt with in the HDLC deencapsulation, anyway. */
947            struct pptp_set_link_info *packet =
948                (struct pptp_set_link_info *)buffer;
949            /* log it. */
950            log("PPTP_SET_LINK_INFO received from peer_callid %u",
951                    (unsigned int) ntoh16(packet->call_id_peer));
952            log("  send_accm is %08lX, recv_accm is %08lX",
953                    (unsigned long) ntoh32(packet->send_accm),
954                    (unsigned long) ntoh32(packet->recv_accm));
955            if (!(ntoh32(packet->send_accm) == 0 &&
956                    ntoh32(packet->recv_accm) == 0))
957                warn("Non-zero Async Control Character Maps are not supported!");
958            break;
959        }
960        default:
961            log("Unrecognized Packet %d received.",
962                    (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type));
963            /* goto pptp_conn_close; */
964            break;
965    }
966    return 0;
967pptp_conn_close:
968    warn("pptp_conn_close(%d)", (int) close_reason);
969    pptp_conn_close(conn, close_reason);
970    return 0;
971}
972
973/*** pptp_set_link **************************************************************/
974void pptp_set_link(PPTP_CONN* conn, int peer_call_id)
975{
976    int idx, rc;
977    /* if we need to send a set_link packet because of buggy
978       hardware or pptp server, do it now */
979    if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) {
980        struct pptp_set_link_info packet;
981        if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id)))
982            warn("calling the set_link hook failed (%d)", rc);
983        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
984            pptp_reset_timer();
985        }
986    }
987}
988
989/*** Get info from call structure *********************************************/
990/* NOTE: The peer_call_id is undefined until we get a server response. */
991void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
992		       u_int16_t * call_id, u_int16_t * peer_call_id)
993{
994    assert(conn != NULL); assert(call != NULL);
995    *call_id = call->call_id;
996    *peer_call_id = call->peer_call_id;
997}
998
999/*** pptp_call_closure_put ****************************************************/
1000void   pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl)
1001{
1002    assert(conn != NULL); assert(call != NULL);
1003    call->closure = cl;
1004}
1005
1006/*** pptp_call_closure_get ****************************************************/
1007void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call)
1008{
1009    assert(conn != NULL); assert(call != NULL);
1010    return call->closure;
1011}
1012
1013/*** pptp_conn_closure_put ****************************************************/
1014void   pptp_conn_closure_put(PPTP_CONN * conn, void *cl)
1015{
1016    assert(conn != NULL);
1017    conn->closure = cl;
1018}
1019
1020/*** pptp_conn_closure_get ****************************************************/
1021void * pptp_conn_closure_get(PPTP_CONN * conn)
1022{
1023    assert(conn != NULL);
1024    return conn->closure;
1025}
1026
1027/*** Reset keep-alive timer ***************************************************/
1028static void pptp_reset_timer(void)
1029{
1030    const struct itimerval tv = { {  0, 0 },   /* stop on time-out */
1031        { idle_wait, 0 } };
1032    if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL);
1033}
1034
1035
1036/*** Handle keep-alive timer **************************************************/
1037static void pptp_handle_timer()
1038{
1039    int i;
1040    /* "Keep Alives and Timers, 1": check connection state */
1041    if (global.conn->conn_state != CONN_ESTABLISHED) {
1042        if (global.conn->conn_state == CONN_WAIT_STOP_REPLY)
1043            /* hard close. */
1044            pptp_conn_destroy(global.conn);
1045        else /* soft close */
1046            pptp_conn_close(global.conn, PPTP_STOP_NONE);
1047    }
1048    /* "Keep Alives and Timers, 2": check echo status */
1049    if (global.conn->ka_state == KA_OUTSTANDING) {
1050        /* no response to keep-alive */
1051        log ("closing control connection due to missing echo reply");
1052	pptp_conn_close(global.conn, PPTP_STOP_NONE);
1053    } else { /* ka_state == NONE */ /* send keep-alive */
1054        struct pptp_echo_rqst rqst = {
1055            PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) };
1056        pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst));
1057        global.conn->ka_state = KA_OUTSTANDING;
1058    }
1059    /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */
1060    for (i = 0; i < vector_size(global.conn->call); i++) {
1061        PPTP_CALL * call = vector_get_Nth(global.conn->call, i);
1062        if (call->call_type == PPTP_CALL_PNS) {
1063            if (call->state.pns == PNS_WAIT_REPLY) {
1064                /* send close request */
1065                pptp_call_close(global.conn, call);
1066                assert(call->state.pns == PNS_WAIT_DISCONNECT);
1067            } else if (call->state.pns == PNS_WAIT_DISCONNECT) {
1068                /* hard-close the call */
1069                pptp_call_destroy(global.conn, call);
1070            }
1071        } else if (call->call_type == PPTP_CALL_PAC) {
1072            if (call->state.pac == PAC_WAIT_REPLY) {
1073                /* XXX FIXME -- drop the PAC connection XXX */
1074            } else if (call->state.pac == PAC_WAIT_CS_ANS) {
1075                /* XXX FIXME -- drop the PAC connection XXX */
1076            }
1077        }
1078    }
1079    pptp_reset_timer();
1080}
1081