1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
1 |
/*
|
2 |
* OpenVPN -- An application to securely tunnel IP networks
|
|
3 |
* over a single TCP/UDP port, with support for SSL/TLS-based
|
|
4 |
* session authentication and key exchange,
|
|
5 |
* packet encryption, packet authentication, and
|
|
6 |
* packet compression.
|
|
7 |
*
|
|
1.1.2
by Alberto Gonzalez Iniesta
Import upstream version 2.0.2 |
8 |
* Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
|
1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
9 |
*
|
10 |
* This program is free software; you can redistribute it and/or modify
|
|
1.1.2
by Alberto Gonzalez Iniesta
Import upstream version 2.0.2 |
11 |
* it under the terms of the GNU General Public License version 2
|
12 |
* as published by the Free Software Foundation.
|
|
1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
13 |
*
|
14 |
* This program is distributed in the hope that it will be useful,
|
|
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17 |
* GNU General Public License for more details.
|
|
18 |
*
|
|
19 |
* You should have received a copy of the GNU General Public License
|
|
20 |
* along with this program (see the file COPYING included with this
|
|
21 |
* distribution); if not, write to the Free Software Foundation, Inc.,
|
|
22 |
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
23 |
*/
|
|
24 |
||
25 |
#ifdef WIN32
|
|
26 |
#include "config-win32.h" |
|
27 |
#else
|
|
28 |
#include "config.h" |
|
29 |
#endif
|
|
30 |
||
31 |
#include "syshead.h" |
|
32 |
||
33 |
#include "push.h" |
|
34 |
#include "options.h" |
|
35 |
#include "ssl.h" |
|
36 |
#include "manage.h" |
|
37 |
||
38 |
#include "memdbg.h" |
|
39 |
||
40 |
#if P2MP
|
|
41 |
||
42 |
/*
|
|
43 |
* Auth username/password
|
|
44 |
*
|
|
45 |
* Client received an authentication failed message from server.
|
|
46 |
* Runs on client.
|
|
47 |
*/
|
|
48 |
void
|
|
49 |
receive_auth_failed (struct context *c, const struct buffer *buffer) |
|
50 |
{
|
|
51 |
msg (M_VERB0, "AUTH: Received AUTH_FAILED control message"); |
|
52 |
if (c->options.pull) |
|
53 |
{
|
|
1.1.2
by Alberto Gonzalez Iniesta
Import upstream version 2.0.2 |
54 |
switch (auth_retry_get ()) |
55 |
{
|
|
56 |
case AR_NONE: |
|
57 |
c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ |
|
58 |
break; |
|
59 |
case AR_INTERACT: |
|
60 |
ssl_purge_auth (); |
|
61 |
case AR_NOINTERACT: |
|
62 |
c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ |
|
63 |
break; |
|
64 |
default: |
|
65 |
ASSERT (0); |
|
66 |
}
|
|
1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
67 |
c->sig->signal_text = "auth-failure"; |
68 |
#ifdef ENABLE_MANAGEMENT
|
|
69 |
if (management) |
|
70 |
management_auth_failure (management, UP_TYPE_AUTH); |
|
71 |
#endif
|
|
72 |
}
|
|
73 |
}
|
|
74 |
||
75 |
#if P2MP_SERVER
|
|
76 |
/*
|
|
77 |
* Send auth failed message from server to client.
|
|
78 |
*/
|
|
79 |
bool
|
|
80 |
send_auth_failed (struct context *c) |
|
81 |
{
|
|
82 |
return send_control_channel_string (c, "AUTH_FAILED", D_PUSH); |
|
83 |
}
|
|
84 |
#endif
|
|
85 |
||
86 |
/*
|
|
87 |
* Push/Pull
|
|
88 |
*/
|
|
89 |
||
90 |
void
|
|
91 |
incoming_push_message (struct context *c, const struct buffer *buffer) |
|
92 |
{
|
|
93 |
struct gc_arena gc = gc_new (); |
|
94 |
unsigned int option_types_found = 0; |
|
95 |
int status; |
|
96 |
||
97 |
msg (D_PUSH, "PUSH: Received control message: '%s'", BSTR (buffer)); |
|
98 |
||
99 |
status = process_incoming_push_msg (c, |
|
100 |
buffer, |
|
101 |
c->options.pull, |
|
102 |
pull_permission_mask (), |
|
103 |
&option_types_found); |
|
104 |
||
105 |
if (status == PUSH_MSG_ERROR) |
|
106 |
msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (buffer)); |
|
107 |
else if (status == PUSH_MSG_REPLY) |
|
108 |
{
|
|
109 |
do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */ |
|
110 |
event_timeout_clear (&c->c2.push_request_interval); |
|
111 |
}
|
|
112 |
||
113 |
gc_free (&gc); |
|
114 |
}
|
|
115 |
||
116 |
bool
|
|
117 |
send_push_request (struct context *c) |
|
118 |
{
|
|
119 |
return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH); |
|
120 |
}
|
|
121 |
||
122 |
#if P2MP_SERVER
|
|
123 |
bool
|
|
124 |
send_push_reply (struct context *c) |
|
125 |
{
|
|
126 |
struct gc_arena gc = gc_new (); |
|
127 |
struct buffer buf = alloc_buf_gc (MAX_PUSH_LIST_LEN + 256, &gc); |
|
128 |
bool ret = false; |
|
129 |
||
130 |
buf_printf (&buf, "PUSH_REPLY"); |
|
131 |
||
132 |
if (c->options.push_list && strlen (c->options.push_list->options)) |
|
133 |
buf_printf (&buf, ",%s", c->options.push_list->options); |
|
134 |
||
135 |
if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask) |
|
136 |
buf_printf (&buf, ",ifconfig %s %s", |
|
137 |
print_in_addr_t (c->c2.push_ifconfig_local, 0, &gc), |
|
138 |
print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); |
|
139 |
||
1.1.2
by Alberto Gonzalez Iniesta
Import upstream version 2.0.2 |
140 |
if (strlen (BSTR (&buf)) < MAX_PUSH_LIST_LEN) |
141 |
ret = send_control_channel_string (c, BSTR (&buf), D_PUSH); |
|
142 |
else
|
|
143 |
msg (M_WARN, "Maximum length of --push buffer (%d) has been exceeded", MAX_PUSH_LIST_LEN); |
|
1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
144 |
|
145 |
gc_free (&gc); |
|
146 |
return ret; |
|
147 |
}
|
|
148 |
||
149 |
void
|
|
150 |
push_option (struct options *o, const char *opt, int msglevel) |
|
151 |
{
|
|
152 |
int len; |
|
153 |
bool first = false; |
|
154 |
||
155 |
if (!string_class (opt, CC_ANY, CC_COMMA)) |
|
156 |
{
|
|
157 |
msg (msglevel, "PUSH OPTION FAILED (illegal comma (',') in string): '%s'", opt); |
|
158 |
}
|
|
159 |
else
|
|
160 |
{
|
|
161 |
if (!o->push_list) |
|
162 |
{
|
|
163 |
ALLOC_OBJ_CLEAR_GC (o->push_list, struct push_list, &o->gc); |
|
164 |
first = true; |
|
165 |
}
|
|
166 |
||
167 |
len = strlen (o->push_list->options); |
|
168 |
if (len + strlen (opt) + 2 >= MAX_PUSH_LIST_LEN) |
|
169 |
{
|
|
170 |
msg (msglevel, "Maximum length of --push buffer (%d) has been exceeded", MAX_PUSH_LIST_LEN); |
|
171 |
}
|
|
172 |
else
|
|
173 |
{
|
|
174 |
if (!first) |
|
175 |
strcat (o->push_list->options, ","); |
|
176 |
strcat (o->push_list->options, opt); |
|
177 |
}
|
|
178 |
}
|
|
179 |
}
|
|
180 |
||
181 |
void
|
|
182 |
push_reset (struct options *o) |
|
183 |
{
|
|
184 |
o->push_list = NULL; |
|
185 |
}
|
|
186 |
#endif
|
|
187 |
||
188 |
int
|
|
189 |
process_incoming_push_msg (struct context *c, |
|
190 |
const struct buffer *buffer, |
|
191 |
bool honor_received_options, |
|
192 |
unsigned int permission_mask, |
|
1.1.2
by Alberto Gonzalez Iniesta
Import upstream version 2.0.2 |
193 |
unsigned int *option_types_found) |
1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
194 |
{
|
195 |
int ret = PUSH_MSG_ERROR; |
|
196 |
struct buffer buf = *buffer; |
|
197 |
||
198 |
#if P2MP_SERVER
|
|
199 |
if (buf_string_compare_advance (&buf, "PUSH_REQUEST")) |
|
200 |
{
|
|
201 |
if (!tls_authenticated (c->c2.tls_multi) || c->c2.context_auth == CAS_FAILED) |
|
202 |
{
|
|
203 |
send_auth_failed (c); |
|
204 |
schedule_exit (c, c->options.scheduled_exit_interval); |
|
205 |
ret = PUSH_MSG_AUTH_FAILURE; |
|
206 |
}
|
|
207 |
else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) |
|
208 |
{
|
|
209 |
if (send_push_reply (c)) |
|
210 |
ret = PUSH_MSG_REQUEST; |
|
211 |
}
|
|
212 |
else
|
|
213 |
{
|
|
214 |
ret = PUSH_MSG_REQUEST_DEFERRED; |
|
215 |
}
|
|
216 |
}
|
|
217 |
else
|
|
218 |
#endif
|
|
219 |
||
220 |
if (honor_received_options && buf_string_compare_advance (&buf, "PUSH_REPLY")) |
|
221 |
{
|
|
222 |
const uint8_t ch = buf_read_u8 (&buf); |
|
223 |
if (ch == ',') |
|
224 |
{
|
|
225 |
pre_pull_restore (&c->options); |
|
226 |
c->c2.pulled_options_string = string_alloc (BSTR (&buf), &c->c2.gc); |
|
227 |
if (apply_push_options (&c->options, |
|
228 |
&buf, |
|
229 |
permission_mask, |
|
230 |
option_types_found, |
|
231 |
c->c2.es)) |
|
232 |
ret = PUSH_MSG_REPLY; |
|
233 |
}
|
|
234 |
else if (ch == '\0') |
|
235 |
{
|
|
236 |
ret = PUSH_MSG_REPLY; |
|
237 |
}
|
|
238 |
/* show_settings (&c->options); */
|
|
239 |
}
|
|
240 |
return ret; |
|
241 |
}
|
|
242 |
||
243 |
#if P2MP_SERVER
|
|
244 |
/*
|
|
245 |
* Remove iroutes from the push_list.
|
|
246 |
*/
|
|
247 |
void
|
|
248 |
remove_iroutes_from_push_route_list (struct options *o) |
|
249 |
{
|
|
250 |
if (o && o->push_list && o->iroutes) |
|
251 |
{
|
|
252 |
struct gc_arena gc = gc_new (); |
|
253 |
struct push_list *pl; |
|
254 |
struct buffer in, out; |
|
255 |
char *line; |
|
256 |
bool first = true; |
|
257 |
||
258 |
/* prepare input and output buffers */
|
|
259 |
ALLOC_OBJ_CLEAR_GC (pl, struct push_list, &gc); |
|
260 |
ALLOC_ARRAY_CLEAR_GC (line, char, MAX_PUSH_LIST_LEN, &gc); |
|
261 |
||
1.1.2
by Alberto Gonzalez Iniesta
Import upstream version 2.0.2 |
262 |
buf_set_read (&in, (const uint8_t*) o->push_list->options, strlen (o->push_list->options)); |
263 |
buf_set_write (&out, (uint8_t*) pl->options, sizeof (pl->options)); |
|
1.1.1
by Alberto Gonzalez Iniesta
Import upstream version 1.99+2.rc6 |
264 |
|
265 |
/* cycle through the push list */
|
|
266 |
while (buf_parse (&in, ',', line, MAX_PUSH_LIST_LEN)) |
|
267 |
{
|
|
268 |
char *p[MAX_PARMS]; |
|
269 |
bool copy = true; |
|
270 |
||
271 |
/* parse the push item */
|
|
272 |
CLEAR (p); |
|
273 |
if (parse_line (line, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) |
|
274 |
{
|
|
275 |
/* is the push item a route directive? */
|
|
276 |
if (p[0] && p[1] && p[2] && !strcmp (p[0], "route")) |
|
277 |
{
|
|
278 |
/* get route parameters */
|
|
279 |
bool status1, status2; |
|
280 |
const in_addr_t network = getaddr (GETADDR_HOST_ORDER, p[1], 0, &status1, NULL); |
|
281 |
const in_addr_t netmask = getaddr (GETADDR_HOST_ORDER, p[2], 0, &status2, NULL); |
|
282 |
||
283 |
/* did route parameters parse correctly? */
|
|
284 |
if (status1 && status2) |
|
285 |
{
|
|
286 |
const struct iroute *ir; |
|
287 |
||
288 |
/* does route match an iroute? */
|
|
289 |
for (ir = o->iroutes; ir != NULL; ir = ir->next) |
|
290 |
{
|
|
291 |
if (network == ir->network && netmask == netbits_to_netmask (ir->netbits)) |
|
292 |
{
|
|
293 |
copy = false; |
|
294 |
break; |
|
295 |
}
|
|
296 |
}
|
|
297 |
}
|
|
298 |
}
|
|
299 |
}
|
|
300 |
||
301 |
/* should we copy the push item? */
|
|
302 |
if (copy) |
|
303 |
{
|
|
304 |
if (!first) |
|
305 |
buf_printf (&out, ","); |
|
306 |
buf_printf (&out, "%s", line); |
|
307 |
first = false; |
|
308 |
}
|
|
309 |
else
|
|
310 |
msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", line); |
|
311 |
}
|
|
312 |
||
313 |
#if 0
|
|
314 |
msg (M_INFO, "BEFORE: '%s'", o->push_list->options);
|
|
315 |
msg (M_INFO, "AFTER: '%s'", pl->options);
|
|
316 |
#endif
|
|
317 |
||
318 |
/* copy new push list back to options */
|
|
319 |
*o->push_list = *pl; |
|
320 |
||
321 |
gc_free (&gc); |
|
322 |
}
|
|
323 |
}
|
|
324 |
#endif
|
|
325 |
||
326 |
#endif
|