bool buf_parse (struct buffer *buf, const int delim, char *line, const int size) { bool eol = false; int n = 0; int c; ASSERT (size > 0); do { c = buf_read_u8 (buf); if (c < 0) eol = true; if (c <= 0 || c == delim) c = 0; if (n >= size) break; line[n++] = c; } while (c); line[size-1] = '\0'; return !(eol && !strlen (line)); }
/* * 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? */ /* advance to next server? */ { bool purge = true; if (m[0] == '[') { int i; for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) { if (m[i] == 'P') { purge = false; } else if (m[i] == 'N') { /* next server? */ c->options.no_advance = 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 } }
static bool tls_crypt_v2_verify_metadata(const struct tls_wrap_ctx *ctx, const struct tls_options *opt) { bool ret = false; struct gc_arena gc = gc_new(); const char *tmp_file = NULL; struct buffer metadata = ctx->tls_crypt_v2_metadata; int metadata_type = buf_read_u8(&metadata); if (metadata_type < 0) { msg(M_WARN, "ERROR: no metadata type"); goto cleanup; } tmp_file = platform_create_temp_file(opt->tmp_dir, "tls_crypt_v2_metadata_", &gc); if (!tmp_file || !buffer_write_file(tmp_file, &metadata)) { msg(M_WARN, "ERROR: could not write metadata to file"); goto cleanup; } char metadata_type_str[4] = { 0 }; /* Max value: 255 */ openvpn_snprintf(metadata_type_str, sizeof(metadata_type_str), "%i", metadata_type); struct env_set *es = env_set_create(NULL); setenv_str(es, "script_type", "tls-crypt-v2-verify"); setenv_str(es, "metadata_type", metadata_type_str); setenv_str(es, "metadata_file", tmp_file); struct argv argv = argv_new(); argv_parse_cmd(&argv, opt->tls_crypt_v2_verify_script); argv_msg_prefix(D_TLS_DEBUG, &argv, "Executing tls-crypt-v2-verify"); ret = openvpn_run_script(&argv, es, 0, "--tls-crypt-v2-verify"); argv_reset(&argv); env_set_destroy(es); if (!platform_unlink(tmp_file)) { msg(M_WARN, "WARNING: failed to remove temp file '%s", tmp_file); } if (ret) { msg(D_HANDSHAKE, "TLS CRYPT V2 VERIFY SCRIPT OK"); } else { msg(D_HANDSHAKE, "TLS CRYPT V2 VERIFY SCRIPT ERROR"); } cleanup: gc_free(&gc); return ret; }
bool status_read(struct status_output *so, struct buffer *buf) { bool ret = false; if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_READ)) { ASSERT(buf_defined(&so->read_buf)); ASSERT(buf_defined(buf)); while (true) { const int c = buf_read_u8(&so->read_buf); /* read more of file into buffer */ if (c == -1) { int len; ASSERT(buf_init(&so->read_buf, 0)); len = read(so->fd, BPTR(&so->read_buf), BCAP(&so->read_buf)); if (len <= 0) { break; } ASSERT(buf_inc_len(&so->read_buf, len)); continue; } ret = true; if (c == '\r') { continue; } if (c == '\n') { break; } buf_write_u8(buf, c); } buf_null_terminate(buf); } return ret; }
int buf_substring_len (const struct buffer *buf, int delim) { int i = 0; struct buffer tmp = *buf; int c; while ((c = buf_read_u8 (&tmp)) >= 0) { ++i; if (c == delim) return i; } return -1; }
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")) { ret = process_incoming_push_request(c); } 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_digest_init_done) { c->c2.pulled_options_state = md_ctx_new(); md_ctx_init(c->c2.pulled_options_state, md_kt_get("SHA256")); c->c2.pulled_options_digest_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)) { push_update_digest(c->c2.pulled_options_state, &buf_orig, &c->options); switch (c->options.push_continuation) { case 0: case 1: md_ctx_final(c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); md_ctx_cleanup(c->c2.pulled_options_state); md_ctx_free(c->c2.pulled_options_state); c->c2.pulled_options_state = NULL; c->c2.pulled_options_digest_init_done = false; ret = PUSH_MSG_REPLY; break; case 2: ret = PUSH_MSG_CONTINUATION; break; } } } else if (ch == '\0') { ret = PUSH_MSG_REPLY; } /* show_settings (&c->options); */ } return ret; }
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.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; }
void process_received_occ_msg (struct context *c) { ASSERT (buf_advance (&c->c2.buf, OCC_STRING_SIZE)); switch (buf_read_u8 (&c->c2.buf)) { case OCC_REQUEST: dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REQUEST"); c->c2.occ_op = OCC_REPLY; break; case OCC_MTU_REQUEST: dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST"); c->c2.occ_op = OCC_MTU_REPLY; break; case OCC_MTU_LOAD_REQUEST: dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST"); c->c2.occ_mtu_load_size = buf_read_u16 (&c->c2.buf); if (c->c2.occ_mtu_load_size >= 0) c->c2.occ_op = OCC_MTU_LOAD; break; case OCC_REPLY: dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REPLY"); if (c->options.occ && !TLS_MODE (c) && c->c2.options_string_remote) { if (!options_cmp_equal_safe ((char *) BPTR (&c->c2.buf), c->c2.options_string_remote, c->c2.buf.len)) { options_warning_safe ((char *) BPTR (&c->c2.buf), c->c2.options_string_remote, c->c2.buf.len); } } event_timeout_clear (&c->c2.occ_interval); break; case OCC_MTU_REPLY: dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY"); c->c2.max_recv_size_remote = buf_read_u16 (&c->c2.buf); c->c2.max_send_size_remote = buf_read_u16 (&c->c2.buf); if (c->options.mtu_test && c->c2.max_recv_size_remote > 0 && c->c2.max_send_size_remote > 0) { msg (M_INFO, "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]", c->c2.max_send_size_local, c->c2.max_recv_size_remote, c->c2.max_send_size_remote, c->c2.max_recv_size_local); if (!c->options.fragment && c->options.proto == PROTO_UDPv4 && c->c2.max_send_size_local > TUN_MTU_MIN && (c->c2.max_recv_size_remote < c->c2.max_send_size_local || c->c2.max_recv_size_local < c->c2.max_send_size_remote)) msg (M_INFO, "NOTE: This connection is unable to accomodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.", c->c2.max_send_size_local); } event_timeout_clear (&c->c2.occ_mtu_load_test_interval); break; case OCC_EXIT: dmsg (D_PACKET_CONTENT, "RECEIVED OCC_EXIT"); c->sig->signal_received = SIGTERM; c->sig->signal_text = "remote-exit"; break; } c->c2.buf.len = 0; /* don't pass packet on */ }