/* * Configure PATH. On Windows, sometimes PATH is not set correctly * by default. */ static void configure_win_path (void) { static bool done = false; /* GLOBAL */ if (!done) { FILE *fp; fp = fopen ("c:\\windows\\system32\\route.exe", "rb"); if (fp) { const int bufsiz = 4096; struct gc_arena gc = gc_new (); struct buffer oldpath = alloc_buf_gc (bufsiz, &gc); struct buffer newpath = alloc_buf_gc (bufsiz, &gc); const char* delim = ";"; DWORD status; fclose (fp); status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); #if 0 status = 0; #endif if (!status) { *BPTR(&oldpath) = '\0'; delim = ""; } buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s", delim, BSTR(&oldpath)); SetEnvironmentVariable ("PATH", BSTR(&newpath)); #if 0 status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); if (status > 0) printf ("PATH: %s\n", BSTR(&oldpath)); #endif gc_free (&gc); done = true; } } }
bool crypto_pem_decode(const char *name, struct buffer *dst, const struct buffer *src) { bool ret = false; BIO *bio = BIO_new_mem_buf((char *)BPTR(src), BLEN(src)); if (!bio) { crypto_msg(M_FATAL, "Cannot open memory BIO for PEM decode"); } char *name_read = NULL; char *header_read = NULL; uint8_t *data_read = NULL; long data_read_len = 0; if (!PEM_read_bio(bio, &name_read, &header_read, &data_read, &data_read_len)) { dmsg(D_CRYPT_ERRORS, "%s: PEM decode failed", __func__); goto cleanup; } if (strcmp(name, name_read)) { dmsg(D_CRYPT_ERRORS, "%s: unexpected PEM name (got '%s', expected '%s')", __func__, name_read, name); goto cleanup; } uint8_t *dst_data = buf_write_alloc(dst, data_read_len); if (!dst_data) { dmsg(D_CRYPT_ERRORS, "%s: dst too small (%i, needs %li)", __func__, BCAP(dst), data_read_len); goto cleanup; } memcpy(dst_data, data_read, data_read_len); ret = true; cleanup: OPENSSL_free(name_read); OPENSSL_free(header_read); OPENSSL_free(data_read); if (!BIO_free(bio)) { ret = false;; } 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; }
static int proxy_connection_io_recv (struct proxy_connection *pc) { /* recv data from socket */ const int status = recv (pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL); if (status < 0) { return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_READ_ERROR; } else { if (!status) return IOSTAT_READ_ERROR; pc->buf.len = status; } return IOSTAT_GOOD; }
static int proxy_connection_io_recv (struct proxy_connection *pc) { /* recv data from socket */ const int status = recv (pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL); if (status < 0) { return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_READ_ERROR; } else { if (!status) return IOSTAT_READ_ERROR; dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: read[%d] %d", (int)pc->sd, status); pc->buf.len = status; } return IOSTAT_GOOD; }
/* * This function runs in the context of the background proxy process. * Receive a control message from the parent (sent by the port_share_sendmsg * function above) and act on it. Return false if the proxy process should * exit, true otherwise. */ static bool control_message_from_parent (const socket_descriptor_t sd_control, struct proxy_connection **list, struct event_set *es, const in_addr_t server_addr, const int server_port, const int max_initial_buf, const char *journal_dir) { /* this buffer needs to be large enough to handle the largest buffer that might be returned by the link_socket_read call in read_incoming_link. */ struct buffer buf = alloc_buf (max_initial_buf); struct msghdr mesg; struct cmsghdr* h; struct iovec iov[2]; char command = 0; ssize_t status; int ret = true; CLEAR (mesg); iov[0].iov_base = &command; iov[0].iov_len = sizeof (command); iov[1].iov_base = BPTR (&buf); iov[1].iov_len = BCAP (&buf); mesg.msg_iov = iov; mesg.msg_iovlen = 2; mesg.msg_controllen = cmsg_size (); mesg.msg_control = (char *) malloc (mesg.msg_controllen); check_malloc_return (mesg.msg_control); mesg.msg_flags = 0; h = CMSG_FIRSTHDR(&mesg); h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); h->cmsg_level = SOL_SOCKET; h->cmsg_type = SCM_RIGHTS; *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED; status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL); if (status != -1) { if ( h == NULL || h->cmsg_len != CMSG_LEN(sizeof(socket_descriptor_t)) || h->cmsg_level != SOL_SOCKET || h->cmsg_type != SCM_RIGHTS ) { msg (M_WARN, "PORT SHARE PROXY: received unknown message"); } else { const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h)); dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd); if (status >= 2 && command == COMMAND_REDIRECT) { buf.len = status - 1; if (proxy_entry_new (list, es, server_addr, server_port, received_fd, &buf, journal_dir)) { CLEAR (buf); /* we gave the buffer to proxy_entry_new */ } else { openvpn_close_socket (received_fd); } } else if (status >= 1 && command == COMMAND_EXIT) { dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT"); openvpn_close_socket (received_fd); /* null socket */ ret = false; } } } free (mesg.msg_control); free_buf (&buf); return ret; }
void tls_crypt_v2_write_client_key_file(const char *filename, const char *b64_metadata, const char *server_key_file, const char *server_key_inline) { struct gc_arena gc = gc_new(); struct key_ctx server_key = { 0 }; struct buffer client_key_pem = { 0 }; struct buffer dst = alloc_buf_gc(TLS_CRYPT_V2_CLIENT_KEY_LEN + TLS_CRYPT_V2_MAX_WKC_LEN, &gc); struct key2 client_key = { 2 }; if (!rand_bytes((void *)client_key.keys, sizeof(client_key.keys))) { msg(M_FATAL, "ERROR: could not generate random key"); goto cleanup; } ASSERT(buf_write(&dst, client_key.keys, sizeof(client_key.keys))); struct buffer metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, &gc); if (b64_metadata) { if (TLS_CRYPT_V2_MAX_B64_METADATA_LEN < strlen(b64_metadata)) { msg(M_FATAL, "ERROR: metadata too long (%d bytes, max %u bytes)", (int)strlen(b64_metadata), TLS_CRYPT_V2_MAX_B64_METADATA_LEN); } ASSERT(buf_write(&metadata, &TLS_CRYPT_METADATA_TYPE_USER, 1)); int decoded_len = openvpn_base64_decode(b64_metadata, BPTR(&metadata), BCAP(&metadata)); if (decoded_len < 0) { msg(M_FATAL, "ERROR: failed to base64 decode provided metadata"); goto cleanup; } ASSERT(buf_inc_len(&metadata, decoded_len)); } else { int64_t timestamp = htonll((uint64_t)now); ASSERT(buf_write(&metadata, &TLS_CRYPT_METADATA_TYPE_TIMESTAMP, 1)); ASSERT(buf_write(&metadata, ×tamp, sizeof(timestamp))); } tls_crypt_v2_init_server_key(&server_key, true, server_key_file, server_key_inline); if (!tls_crypt_v2_wrap_client_key(&dst, &client_key, &metadata, &server_key, &gc)) { msg(M_FATAL, "ERROR: could not wrap generated client key"); goto cleanup; } /* PEM-encode Kc || WKc */ if (!crypto_pem_encode(tls_crypt_v2_cli_pem_name, &client_key_pem, &dst, &gc)) { msg(M_FATAL, "ERROR: could not PEM-encode client key"); goto cleanup; } if (!buffer_write_file(filename, &client_key_pem)) { msg(M_FATAL, "ERROR: could not write client key file"); goto cleanup; } /* Sanity check: load client key (as "client") */ struct key_ctx_bi test_client_key; struct buffer test_wrapped_client_key; msg(D_GENKEY, "Testing client-side key loading..."); tls_crypt_v2_init_client_key(&test_client_key, &test_wrapped_client_key, filename, NULL); free_key_ctx_bi(&test_client_key); /* Sanity check: unwrap and load client key (as "server") */ struct buffer test_metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, &gc); struct key2 test_client_key2 = { 0 }; free_key_ctx(&server_key); tls_crypt_v2_init_server_key(&server_key, false, server_key_file, server_key_inline); msg(D_GENKEY, "Testing server-side key loading..."); ASSERT(tls_crypt_v2_unwrap_client_key(&test_client_key2, &test_metadata, test_wrapped_client_key, &server_key)); secure_memzero(&test_client_key2, sizeof(test_client_key2)); free_buf(&test_wrapped_client_key); cleanup: secure_memzero(&client_key, sizeof(client_key)); free_key_ctx(&server_key); buf_clear(&client_key_pem); buf_clear(&dst); gc_free(&gc); }
static bool send_push_reply(struct context *c, struct push_list *per_client_push_list) { struct gc_arena gc = gc_new(); struct buffer buf = alloc_buf_gc(PUSH_BUNDLE_SIZE, &gc); bool multi_push = false; const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ const int safe_cap = BCAP(&buf) - extra; bool push_sent = false; buf_printf(&buf, "%s", push_reply_cmd); /* send options which are common to all clients */ if (!send_push_options(c, &buf, &c->options.push_list, safe_cap, &push_sent, &multi_push)) { goto fail; } /* send client-specific options */ if (!send_push_options(c, &buf, per_client_push_list, safe_cap, &push_sent, &multi_push)) { goto fail; } if (multi_push) { buf_printf(&buf, ",push-continuation 1"); } if (BLEN(&buf) > sizeof(push_reply_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", push_reply_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; }
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; #ifdef ENABLE_CLIENT_NAT if (c->c2.push_ifconfig_local_alias) ifconfig_local = c->c2.push_ifconfig_local_alias; #endif 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"); 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; }