diff options
Diffstat (limited to 'main/openvpn/src/openvpn/push.c')
m--------- | main/openvpn | 0 | ||||
-rw-r--r-- | main/openvpn/src/openvpn/push.c | 566 |
2 files changed, 0 insertions, 566 deletions
diff --git a/main/openvpn b/main/openvpn new file mode 160000 +Subproject 7aaf01766f9718375986600216607aeb6397200 diff --git a/main/openvpn/src/openvpn/push.c b/main/openvpn/src/openvpn/push.c deleted file mode 100644 index 385be1d5..00000000 --- a/main/openvpn/src/openvpn/push.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single TCP/UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#elif defined(_MSC_VER) -#include "config-msvc.h" -#endif - -#include "syshead.h" - -#include "push.h" -#include "options.h" -#include "ssl.h" -#include "ssl_verify.h" -#include "manage.h" - -#include "memdbg.h" - -#if P2MP - -/* - * Auth username/password - * - * Client received an authentication failed message from server. - * Runs on client. - */ -void -receive_auth_failed (struct context *c, const struct buffer *buffer) -{ - msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); - c->options.no_advance=true; - - if (c->options.pull) - { - switch (auth_retry_get ()) - { - case AR_NONE: - c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ - break; - case AR_INTERACT: - ssl_purge_auth (false); - case AR_NOINTERACT: - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ - break; - default: - ASSERT (0); - } - c->sig->signal_text = "auth-failure"; -#ifdef ENABLE_MANAGEMENT - if (management) - { - const char *reason = NULL; - struct buffer buf = *buffer; - if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) - reason = BSTR (&buf); - management_auth_failure (management, UP_TYPE_AUTH, reason); - } else -#endif - { -#ifdef ENABLE_CLIENT_CR - struct buffer buf = *buffer; - if (buf_string_match_head_str (&buf, "AUTH_FAILED,CRV1:") && BLEN (&buf)) - { - buf_advance (&buf, 12); /* Length of "AUTH_FAILED," substring */ - ssl_put_auth_challenge (BSTR (&buf)); - } -#endif - } - } -} - -/* - * Act on received restart message from server - */ -void -server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv) -{ - if (c->options.pull) - { - struct buffer buf = *buffer; - const char *m = ""; - if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf)) - m = BSTR (&buf); - - /* preserve cached passwords? */ - { - bool purge = true; - - if (m[0] == '[') - { - int i; - for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) - { - if (m[i] == 'P') - purge = false; - } - } - if (purge) - ssl_purge_auth (true); - } - - if (restart) - { - msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ - c->sig->signal_text = "server-pushed-connection-reset"; - } - else - { - msg (D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m); - c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */ - c->sig->signal_text = "server-pushed-halt"; - } -#ifdef ENABLE_MANAGEMENT - if (management) - management_notify (management, "info", c->sig->signal_text, m); -#endif - } -} - -#if P2MP_SERVER - -/* - * Send auth failed message from server to client. - */ -void -send_auth_failed (struct context *c, const char *client_reason) -{ - struct gc_arena gc = gc_new (); - static const char auth_failed[] = "AUTH_FAILED"; - size_t len; - - schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); - - len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed); - if (len > PUSH_BUNDLE_SIZE) - len = PUSH_BUNDLE_SIZE; - - { - struct buffer buf = alloc_buf_gc (len, &gc); - buf_printf (&buf, auth_failed); - if (client_reason) - buf_printf (&buf, ",%s", client_reason); - send_control_channel_string (c, BSTR (&buf), D_PUSH); - } - - gc_free (&gc); -} - -/* - * Send restart message from server to client. - */ -void -send_restart (struct context *c, const char *kill_msg) -{ - schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); - send_control_channel_string (c, kill_msg ? kill_msg : "RESTART", D_PUSH); -} - -#endif - -/* - * Push/Pull - */ - -void -incoming_push_message (struct context *c, const struct buffer *buffer) -{ - struct gc_arena gc = gc_new (); - unsigned int option_types_found = 0; - int status; - - msg (D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc)); - - status = process_incoming_push_msg (c, - buffer, - c->options.pull, - pull_permission_mask (c), - &option_types_found); - - if (status == PUSH_MSG_ERROR) - msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); - else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) - { - c->options.push_option_types_found |= option_types_found; - - if (status == PUSH_MSG_REPLY) - do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */ - event_timeout_clear (&c->c2.push_request_interval); - } - - gc_free (&gc); -} - -bool -send_push_request (struct context *c) -{ - const int max_push_requests = c->options.handshake_window / PUSH_REQUEST_INTERVAL; - if (++c->c2.n_sent_push_requests <= max_push_requests) - { - return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH); - } - else - { - msg (D_STREAM_ERRORS, "No reply from server after sending %d push requests", max_push_requests); - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ - c->sig->signal_text = "no-push-reply"; - return false; - } -} - -#if P2MP_SERVER - -bool -send_push_reply (struct context *c) -{ - struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc); - struct push_entry *e = c->options.push_list.head; - bool multi_push = false; - static char cmd[] = "PUSH_REPLY"; - const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ - const int safe_cap = BCAP (&buf) - extra; - bool push_sent = false; - - msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap ); - - buf_printf (&buf, "%s", cmd); - - if ( c->c2.push_ifconfig_ipv6_defined ) - { - /* IPv6 is put into buffer first, could be lengthy */ - buf_printf( &buf, ",ifconfig-ipv6 %s/%d %s", - print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc), - c->c2.push_ifconfig_ipv6_netbits, - print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) ); - if (BLEN (&buf) >= safe_cap) - { - msg (M_WARN, "--push ifconfig-ipv6 option is too long"); - goto fail; - } - } - - while (e) - { - if (e->enable) - { - const int l = strlen (e->option); - if (BLEN (&buf) + l >= safe_cap) - { - buf_printf (&buf, ",push-continuation 2"); - { - const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); - if (!status) - goto fail; - push_sent = true; - multi_push = true; - buf_reset_len (&buf); - buf_printf (&buf, "%s", cmd); - } - } - if (BLEN (&buf) + l >= safe_cap) - { - msg (M_WARN, "--push option is too long"); - goto fail; - } - buf_printf (&buf, ",%s", e->option); - } - e = e->next; - } - - if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask) - { - in_addr_t ifconfig_local = c->c2.push_ifconfig_local; - if (c->c2.push_ifconfig_local_alias) - ifconfig_local = c->c2.push_ifconfig_local_alias; - buf_printf (&buf, ",ifconfig %s %s", - print_in_addr_t (ifconfig_local, 0, &gc), - print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); - } - if (multi_push) - buf_printf (&buf, ",push-continuation 1"); - - /* Send peer-id if client supports it */ - if (c->c2.tls_multi->peer_info) - { - const char* proto_str = strstr(c->c2.tls_multi->peer_info, "IV_PROTO="); - if (proto_str) - { - int proto = 0; - int r = sscanf(proto_str, "IV_PROTO=%d", &proto); - if ((r == 1) && (proto >= 2)) - buf_printf(&buf, ",peer-id %d", c->c2.tls_multi->peer_id); - } - } - - if (BLEN (&buf) > sizeof(cmd)-1) - { - const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); - if (!status) - goto fail; - push_sent = true; - } - - /* If nothing have been pushed, send an empty push, - * as the client is expecting a response - */ - if (!push_sent) - { - bool status = false; - - buf_reset_len (&buf); - buf_printf (&buf, "%s", cmd); - status = send_control_channel_string (c, BSTR(&buf), D_PUSH); - if (!status) - goto fail; - } - - gc_free (&gc); - return true; - - fail: - gc_free (&gc); - return false; -} - -static void -push_option_ex (struct options *o, const char *opt, bool enable, int msglevel) -{ - if (!string_class (opt, CC_ANY, CC_COMMA)) - { - msg (msglevel, "PUSH OPTION FAILED (illegal comma (',') in string): '%s'", opt); - } - else - { - struct push_entry *e; - ALLOC_OBJ_CLEAR_GC (e, struct push_entry, &o->gc); - e->enable = true; - e->option = opt; - if (o->push_list.head) - { - ASSERT(o->push_list.tail); - o->push_list.tail->next = e; - o->push_list.tail = e; - } - else - { - ASSERT(!o->push_list.tail); - o->push_list.head = e; - o->push_list.tail = e; - } - } -} - -void -push_option (struct options *o, const char *opt, int msglevel) -{ - push_option_ex (o, opt, true, msglevel); -} - -void -clone_push_list (struct options *o) -{ - if (o->push_list.head) - { - const struct push_entry *e = o->push_list.head; - push_reset (o); - while (e) - { - push_option_ex (o, string_alloc (e->option, &o->gc), true, M_FATAL); - e = e->next; - } - } -} - -void -push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc) -{ - const char **argv = make_extended_arg_array (p, gc); - char *opt = print_argv (argv, gc, 0); - push_option (o, opt, msglevel); -} - -void -push_reset (struct options *o) -{ - CLEAR (o->push_list); -} -#endif - -int -process_incoming_push_msg (struct context *c, - const struct buffer *buffer, - bool honor_received_options, - unsigned int permission_mask, - unsigned int *option_types_found) -{ - int ret = PUSH_MSG_ERROR; - struct buffer buf = *buffer; - -#if P2MP_SERVER - if (buf_string_compare_advance (&buf, "PUSH_REQUEST")) - { - if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) - { - const char *client_reason = tls_client_reason (c->c2.tls_multi); - send_auth_failed (c, client_reason); - ret = PUSH_MSG_AUTH_FAILURE; - } - else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) - { - time_t now; - - openvpn_time(&now); - if (c->c2.sent_push_reply_expiry > now) - { - ret = PUSH_MSG_ALREADY_REPLIED; - } - else - { - if (send_push_reply (c)) - { - ret = PUSH_MSG_REQUEST; - c->c2.sent_push_reply_expiry = now + 30; - } - } - } - else - { - ret = PUSH_MSG_REQUEST_DEFERRED; - } - } - else -#endif - - if (honor_received_options && buf_string_compare_advance (&buf, "PUSH_REPLY")) - { - const uint8_t ch = buf_read_u8 (&buf); - if (ch == ',') - { - struct buffer buf_orig = buf; - if (!c->c2.pulled_options_md5_init_done) - { - md5_state_init (&c->c2.pulled_options_state); - c->c2.pulled_options_md5_init_done = true; - } - if (!c->c2.did_pre_pull_restore) - { - pre_pull_restore (&c->options, &c->c2.gc); - c->c2.did_pre_pull_restore = true; - } - if (apply_push_options (&c->options, - &buf, - permission_mask, - option_types_found, - c->c2.es)) - switch (c->options.push_continuation) - { - case 0: - case 1: - md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); - md5_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest); - c->c2.pulled_options_md5_init_done = false; - ret = PUSH_MSG_REPLY; - break; - case 2: - md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); - ret = PUSH_MSG_CONTINUATION; - break; - } - } - else if (ch == '\0') - { - ret = PUSH_MSG_REPLY; - } - /* show_settings (&c->options); */ - } - return ret; -} - -#if P2MP_SERVER - -/* - * Remove iroutes from the push_list. - */ -void -remove_iroutes_from_push_route_list (struct options *o) -{ - if (o && o->push_list.head && o->iroutes) - { - struct gc_arena gc = gc_new (); - struct push_entry *e = o->push_list.head; - - /* cycle through the push list */ - while (e) - { - char *p[MAX_PARMS]; - bool enable = true; - - /* parse the push item */ - CLEAR (p); - if (parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) - { - /* is the push item a route directive? */ - if (p[0] && !strcmp (p[0], "route") && !p[3]) - { - /* get route parameters */ - bool status1, status2; - const in_addr_t network = getaddr (GETADDR_HOST_ORDER, p[1], 0, &status1, NULL); - const in_addr_t netmask = getaddr (GETADDR_HOST_ORDER, p[2] ? p[2] : "255.255.255.255", 0, &status2, NULL); - - /* did route parameters parse correctly? */ - if (status1 && status2) - { - const struct iroute *ir; - - /* does route match an iroute? */ - for (ir = o->iroutes; ir != NULL; ir = ir->next) - { - if (network == ir->network && netmask == netbits_to_netmask (ir->netbits >= 0 ? ir->netbits : 32)) - { - enable = false; - break; - } - } - } - } - } - - /* should we copy the push item? */ - e->enable = enable; - if (!enable) - msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); - - e = e->next; - } - - gc_free (&gc); - } -} - -#endif - -#endif |