1/*
2 * Copyright (c) 2008, 2012, 2013 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23
24#include "fsm.h"
25
26#include <stdlib.h>
27#include <sys/types.h>
28#include <sys/param.h>
29#include <sys/queue.h>
30
31#include "var.h"
32#include "misc.h"
33#include "session.h"
34#include "isakmp.h"
35#include "ike_session.h"
36#include "isakmp_var.h"
37#include "isakmp_ident.h"
38#include "isakmp_agg.h"
39#include "isakmp_quick.h"
40#include "isakmp_inf.h"
41#include "vpn_control_var.h"
42
43#include "plog.h"
44#include "schedule.h"
45
46void
47fsm_set_state(int *var, int state)
48{
49    *var = state;
50    plog(ASL_LEVEL_DEBUG, "****** state changed to: %s\n", s_isakmp_state(0, 0, state));
51}
52
53
54//================================
55// Version Agnostic Events
56//================================
57void
58fsm_api_handle_connect (struct sockaddr_storage *remote, const int connect_mode)
59{
60
61
62}
63
64void
65fsm_api_handle_disconnect (struct sockaddr_storage *remote, const char *reason)
66{
67
68
69}
70
71void
72fsm_pfkey_handle_acquire (phase2_handle_t *iph2)
73{
74
75
76}
77
78void
79fsm_pfkey_getspi_complete (phase2_handle_t *iph2)
80{
81
82}
83
84void
85fsm_isakmp_initial_pkt (vchar_t *pkt, struct sockaddr_storage *local, struct sockaddr_storage *remote)
86{
87
88
89}
90
91//================================
92// IKEv1 Events
93//================================
94
95int
96fsm_ikev1_phase1_process_payloads (phase1_handle_t *iph1, vchar_t *msg)
97{
98
99    int error = 0;
100#ifdef ENABLE_STATS
101    struct timeval start, end;
102
103    gettimeofday(&start, NULL);
104#endif
105
106    switch (iph1->status) {
107        case IKEV1_STATE_PHASE1_ESTABLISHED:
108            return 0;     // ignore - already established
109
110        case IKEV1_STATE_IDENT_I_MSG1SENT:
111            error = ident_i2recv(iph1, msg);
112            break;
113
114        case IKEV1_STATE_IDENT_I_MSG3SENT:
115            error = ident_i4recv(iph1, msg);
116            break;
117
118        case IKEV1_STATE_IDENT_I_MSG5SENT:
119            error = ident_i6recv(iph1, msg);
120            break;
121
122        case IKEV1_STATE_IDENT_R_START:
123            error = ident_r1recv(iph1, msg);
124            if (error) {
125                plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
126                goto fail;
127            }
128            break;
129
130        case IKEV1_STATE_IDENT_R_MSG2SENT:
131            error = ident_r3recv(iph1, msg);
132            break;
133
134        case IKEV1_STATE_IDENT_R_MSG4SENT:
135            error = ident_r5recv(iph1, msg);
136            break;
137
138        case IKEV1_STATE_AGG_R_START:
139            error = agg_r1recv(iph1, msg);
140            if (error) {
141                plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
142                goto fail;
143            }
144            break;
145
146        case IKEV1_STATE_AGG_I_MSG1SENT:
147            error = agg_i2recv(iph1, msg);
148            break;
149
150        case IKEV1_STATE_AGG_R_MSG2SENT:
151            error = agg_r3recv(iph1, msg);
152            break;
153
154        default:
155            // log invalid state
156            error = -1;
157            break;
158    }
159    if (error)
160        return 0; // ignore error and keep phase 1 handle
161
162    VPTRINIT(iph1->sendbuf);
163    /* turn off schedule */
164    SCHED_KILL(iph1->scr);
165
166    /* send */
167    plog(ASL_LEVEL_DEBUG, "===\n");
168    if ((error = fsm_ikev1_phase1_send_response(iph1, msg))) {
169        plog(ASL_LEVEL_ERR, "failed to process packet.\n");
170        goto fail;
171    }
172
173#ifdef ENABLE_STATS
174    gettimeofday(&end, NULL);
175    syslog(LOG_NOTICE, "%s(%s): %8.6f",
176           "Phase 1", s_isakmp_state(iph1->etype, iph1->side, iph1->status),
177           timedelta(&start, &end));
178#endif
179    if (FSM_STATE_IS_ESTABLISHED(iph1->status))
180        ikev1_phase1_established(iph1);
181
182    return 0;
183
184fail:
185        plog(ASL_LEVEL_ERR, "Phase 1 negotiation failed.\n");
186        ike_session_unlink_phase1(iph1);
187        return error;
188
189}
190
191
192int
193fsm_ikev1_phase1_send_response(phase1_handle_t *iph1, vchar_t *msg)
194{
195
196    int error = 0;
197
198    switch (iph1->status) {
199        case IKEV1_STATE_IDENT_I_START:
200            error = ident_i1send(iph1, msg);
201            break;
202
203        case IKEV1_STATE_IDENT_I_MSG2RCVD:
204            error = ident_i3send(iph1, msg);
205            break;
206
207        case IKEV1_STATE_IDENT_I_MSG4RCVD:
208            error = ident_i5send(iph1, msg);
209            break;
210
211        case IKEV1_STATE_IDENT_I_MSG6RCVD:
212            error = ident_ifinalize(iph1, msg);
213            break;
214
215        case IKEV1_STATE_IDENT_R_MSG1RCVD:
216            error = ident_r2send(iph1, msg);
217            break;
218
219        case IKEV1_STATE_IDENT_R_MSG3RCVD:
220            error = ident_r4send(iph1, msg);
221            break;
222
223        case IKEV1_STATE_IDENT_R_MSG5RCVD:
224            error = ident_r6send(iph1, msg);
225            break;
226
227        case IKEV1_STATE_AGG_I_START:
228            error = agg_i1send(iph1, msg);
229            break;
230
231        case IKEV1_STATE_AGG_I_MSG2RCVD:
232            error = agg_i3send(iph1, msg);
233            break;
234
235        case IKEV1_STATE_AGG_R_MSG1RCVD:
236            error = agg_r2send(iph1, msg);
237            break;
238
239        case IKEV1_STATE_AGG_R_MSG3RCVD:
240            error = agg_rfinalize(iph1, msg);
241            break;
242
243        default:
244            // log invalid state
245            error = -1;
246            break;;
247    }
248
249    if (error) {
250        u_int32_t address;
251        if (iph1->remote->ss_family == AF_INET)
252            address = ((struct sockaddr_in *)iph1->remote)->sin_addr.s_addr;
253        else {
254            address = 0;
255        }
256        vpncontrol_notify_ike_failed(error, FROM_LOCAL, address, 0, NULL);
257    }
258
259    return error;
260}
261
262int
263fsm_ikev1_phase2_process_payloads (phase2_handle_t *iph2, vchar_t *msg)
264{
265
266    int error = 0;
267#ifdef ENABLE_STATS
268    struct timeval start, end;
269
270    gettimeofday(&start, NULL);
271#endif
272
273    switch (iph2->status) {
274            /* ignore a packet */
275        case IKEV1_STATE_PHASE2_ESTABLISHED:
276        case IKEV1_STATE_QUICK_I_GETSPISENT:
277        case IKEV1_STATE_QUICK_R_GETSPISENT:
278            return 0;
279
280        case IKEV1_STATE_QUICK_I_MSG1SENT:
281            error = quick_i2recv(iph2, msg);
282            break;
283
284        case IKEV1_STATE_QUICK_I_MSG3SENT:
285            error = quick_i4recv(iph2, msg);
286            break;
287
288        case IKEV1_STATE_QUICK_R_START:
289            error = quick_r1recv(iph2, msg);
290            break;
291
292        case IKEV1_STATE_QUICK_R_MSG2SENT:
293            error = quick_r3recv(iph2, msg);
294            break;
295
296        default:
297            // log invalid state
298            error = -1;
299            break;
300    }
301
302    if (error) {
303        plog(ASL_LEVEL_ERR, "failed to pre-process packet.\n");
304        if (error == ISAKMP_INTERNAL_ERROR)
305            fatal_error(-1);
306        isakmp_info_send_n1(iph2->ph1, error, NULL);
307        goto fail;
308    }
309
310    /* when using commit bit, status will be reached here. */
311    //if (iph2->status == PHASE2ST_ADDSA)	//%%% BUG FIX - wrong place
312    //	return 0;
313
314    /* free resend buffer */
315    if (iph2->sendbuf == NULL && iph2->status != IKEV1_STATE_QUICK_R_MSG1RCVD) {
316        plog(ASL_LEVEL_ERR,
317             "no buffer found as sendbuf\n");
318        error = -1;
319        goto fail;
320    }
321    VPTRINIT(iph2->sendbuf);
322
323    /* turn off schedule */
324    SCHED_KILL(iph2->scr);
325
326    /* when using commit bit, will be finished here - no more packets to send */
327    if (iph2->status == IKEV1_STATE_QUICK_I_ADDSA)
328        return 0;
329
330    error = fsm_ikev1_phase2_send_response(iph2, msg);
331    if (error) {
332        plog(ASL_LEVEL_ERR, "failed to process packet.\n");
333        goto fail;
334    }
335
336#ifdef ENABLE_STATS
337    gettimeofday(&end, NULL);
338    syslog(LOG_NOTICE, "%s(%s): %8.6f",
339           "Phase 2",
340           s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status),
341           timedelta(&start, &end));
342#endif
343
344    return 0;
345
346fail:
347    plog(ASL_LEVEL_ERR, "Phase 2 negotiation failed.\n");
348    ike_session_unlink_phase2(iph2);
349    return error;
350
351}
352
353int
354fsm_ikev1_phase2_send_response(phase2_handle_t *iph2, vchar_t *msg)
355{
356
357    int error = 0;
358
359    switch (iph2->status) {
360        case IKEV1_STATE_QUICK_R_MSG1RCVD:
361            error = quick_rprep(iph2, msg);
362            break;
363
364        case IKEV1_STATE_QUICK_I_GETSPIDONE:
365            error = quick_i1send(iph2, msg);
366            break;
367
368        case IKEV1_STATE_QUICK_I_MSG2RCVD:
369            error = quick_i3send(iph2, msg);
370            break;
371
372        case IKEV1_STATE_QUICK_R_GETSPIDONE:
373            error = quick_r2send(iph2, msg);
374            break;
375
376        case IKEV1_STATE_QUICK_R_MSG3RCVD:
377            error = quick_r4send(iph2, msg);
378            break;
379
380        case IKEV1_STATE_QUICK_R_COMMIT:
381            error = quick_rfinalize(iph2, msg);
382            break;
383
384        default:
385            // log invalid state
386            error = -1;
387            break;;
388    }
389    return error;
390
391}
392
393