/* * Save X509 fields to environment, using the naming convention: * * X509_{cert_depth}_{name}={value} */ void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) { int i; unsigned char c; const x509_name *name; char s[128]; name = &cert->subject; memset( s, 0, sizeof( s ) ); while( name != NULL ) { char name_expand[64+8]; const char *shortname; if( 0 == oid_get_attr_short_name(&name->oid, &shortname) ) { openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s", cert_depth, shortname); } else { openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?", cert_depth); } for( i = 0; i < name->val.len; i++ ) { if( i >= (int) sizeof( s ) - 1 ) break; c = name->val.p[i]; if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) s[i] = '?'; else s[i] = c; } s[i] = '\0'; /* Check both strings, set environment variable */ string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); string_mod ((char*)s, CC_PRINT, CC_CRLF, '_'); setenv_str_incr (es, name_expand, (char*)s); name = name->next; } }
void setenv_unsigned (struct env_set *es, const char *name, unsigned int value) { char buf[64]; openvpn_snprintf (buf, sizeof(buf), "%u", value); setenv_str (es, name, buf); }
void setenv_int(struct env_set *es, const char *name, int value) { char buf[64]; openvpn_snprintf(buf, sizeof(buf), "%d", value); setenv_str(es, name, buf); }
static char * env_block(const struct env_set *es) { char force_path[256]; char *sysroot = get_win_sys_path(); if (!openvpn_snprintf(force_path, sizeof(force_path), "PATH=%s\\System32;%s;%s\\System32\\Wbem", sysroot, sysroot, sysroot)) { msg(M_WARN, "env_block: default path truncated to %s", force_path); } if (es) { struct env_item *e; char *ret; char *p; size_t nchars = 1; bool path_seen = false; for (e = es->list; e != NULL; e = e->next) { nchars += strlen(e->string) + 1; } nchars += strlen(force_path)+1; ret = (char *) malloc(nchars); check_malloc_return(ret); p = ret; for (e = es->list; e != NULL; e = e->next) { if (env_allowed(e->string)) { strcpy(p, e->string); p += strlen(e->string) + 1; } if (strncmp(e->string, "PATH=", 5 ) == 0) { path_seen = true; } } /* make sure PATH is set */ if (!path_seen) { msg( M_INFO, "env_block: add %s", force_path ); strcpy( p, force_path ); p += strlen(force_path) + 1; } *p = '\0'; return ret; } else { return NULL; } }
void setenv_counter(struct env_set *es, const char *name, counter_type value) { char buf[64]; openvpn_snprintf(buf, sizeof(buf), counter_format, value); setenv_str(es, name, buf); }
void setenv_long_long(struct env_set *es, const char *name, long long value) { char buf[64]; openvpn_snprintf(buf, sizeof(buf), "%"PRIi64, (int64_t)value); setenv_str(es, name, buf); }
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; }
static void plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist) { unsigned int msg_flags = 0; if (!format) { return; } if (!name || name[0] == '\0') { msg(D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name"); return; } if (flags & PLOG_ERR) { msg_flags = M_INFO | M_NONFATAL; } else if (flags & PLOG_WARN) { msg_flags = M_INFO | M_WARN; } else if (flags & PLOG_NOTE) { msg_flags = M_INFO; } else if (flags & PLOG_DEBUG) { msg_flags = D_PLUGIN_DEBUG; } if (flags & PLOG_ERRNO) { msg_flags |= M_ERRNO; } if (flags & PLOG_NOMUTE) { msg_flags |= M_NOMUTE; } if (msg_test(msg_flags)) { struct gc_arena gc; char *msg_fmt; /* Never add instance prefix; not thread safe */ msg_flags |= M_NOIPREFIX; gc_init(&gc); msg_fmt = gc_malloc(ERR_BUF_SIZE, false, &gc); openvpn_snprintf(msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format); x_msg_va(msg_flags, msg_fmt, arglist); gc_free(&gc); } }
bool polar_log_func_line(unsigned int flags, int errval, const char *func, int line) { char prefix[256]; if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line)) return polar_log_err(flags, errval, func); return polar_log_err(flags, errval, prefix); }
/* ************************************** * * Information functions * * Print information for the end user. * ***************************************/ void print_details (struct key_state_ssl * ks_ssl, const char *prefix) { const SSL_CIPHER *ciph; X509 *cert; char s1[256]; char s2[256]; s1[0] = s2[0] = 0; ciph = SSL_get_current_cipher (ks_ssl->ssl); openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s %s", prefix, SSL_get_version (ks_ssl->ssl), SSL_CIPHER_get_version (ciph), SSL_CIPHER_get_name (ciph)); cert = SSL_get_peer_certificate (ks_ssl->ssl); if (cert != NULL) { EVP_PKEY *pkey = X509_get_pubkey (cert); if (pkey != NULL) { if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL && pkey->pkey.rsa->n != NULL) { openvpn_snprintf (s2, sizeof (s2), ", %d bit RSA", BN_num_bits (pkey->pkey.rsa->n)); } else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL && pkey->pkey.dsa->p != NULL) { openvpn_snprintf (s2, sizeof (s2), ", %d bit DSA", BN_num_bits (pkey->pkey.dsa->p)); } EVP_PKEY_free (pkey); } X509_free (cert); } /* The SSL API does not allow us to look at temporary RSA/DH keys, * otherwise we should print their lengths too */ msg (D_HANDSHAKE, "%s%s", s1, s2); }
static PKCS11H_BOOL _pkcs11_openvpn_pin_prompt( void *const global_data, void *const user_data, const pkcs11h_token_id_t token, const unsigned retry, char *const pin, const size_t pin_max ) { struct user_pass token_pass; char prompt[1024]; (void)global_data; (void)user_data; (void)retry; ASSERT(token!=NULL); openvpn_snprintf(prompt, sizeof(prompt), "%s token", token->label); token_pass.defined = false; token_pass.nocache = true; if ( !get_user_pass( &token_pass, NULL, prompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL ) ) { return false; } else { strncpynt(pin, token_pass.password, pin_max); purge_user_pass(&token_pass, true); if (strlen(pin) == 0) { return false; } else { return true; } } }
/* worker method for setenv_x509_track */ static void do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) { char *name_expand; size_t name_expand_size; string_mod (value, CC_ANY, CC_CRLF, '?'); msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); name_expand_size = 64 + strlen (name); name_expand = (char *) malloc (name_expand_size); check_malloc_return (name_expand); openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); setenv_str (es, name_expand, value); free (name_expand); }
/* * Save X509 fields to environment, using the naming convention: * * X509_{cert_depth}_{name}={value} */ void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) { int i, n; int fn_nid; ASN1_OBJECT *fn; ASN1_STRING *val; X509_NAME_ENTRY *ent; const char *objbuf; unsigned char *buf; char *name_expand; size_t name_expand_size; X509_NAME *x509 = X509_get_subject_name (peer_cert); n = X509_NAME_entry_count (x509); for (i = 0; i < n; ++i) { ent = X509_NAME_get_entry (x509, i); if (!ent) continue; fn = X509_NAME_ENTRY_get_object (ent); if (!fn) continue; val = X509_NAME_ENTRY_get_data (ent); if (!val) continue; fn_nid = OBJ_obj2nid (fn); if (fn_nid == NID_undef) continue; objbuf = OBJ_nid2sn (fn_nid); if (!objbuf) continue; buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) continue; name_expand_size = 64 + strlen (objbuf); name_expand = (char *) malloc (name_expand_size); check_malloc_return (name_expand); openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", cert_depth, objbuf); string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_'); setenv_str (es, name_expand, (char*)buf); free (name_expand); OPENSSL_free (buf); } }
static void open_biofp() { const time_t current = time (NULL); const pid_t pid = getpid (); if (biofp_last_open + biofp_reopen_interval < current) close_biofp(); if (!biofp) { char fn[256]; openvpn_snprintf(fn, sizeof(fn), "bio/%d-%d.log", pid, biofp_toggle); biofp = fopen (fn, "w"); ASSERT (biofp); biofp_last_open = time (NULL); biofp_toggle ^= 1; } }
static PKCS11H_BOOL _pkcs11_openvpn_token_prompt( void *const global_data, void *const user_data, const pkcs11h_token_id_t token, const unsigned retry ) { struct user_pass token_resp; (void)global_data; (void)user_data; (void)retry; ASSERT(token!=NULL); CLEAR(token_resp); token_resp.defined = false; token_resp.nocache = true; openvpn_snprintf( token_resp.username, sizeof(token_resp.username), "Please insert %s token", token->label ); if ( !get_user_pass( &token_resp, NULL, "token-insertion-request", GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK|GET_USER_PASS_NOFATAL ) ) { return false; } else { return strcmp(token_resp.password, "ok") == 0; } }
static bool _pkcs11_openvpn_pin_prompt ( IN const void *pData, IN const pkcs11h_token_id_t token, IN const unsigned retry, OUT char * const szPIN, IN const size_t nMaxPIN ) { static struct user_pass token_pass; char szPrompt[1024]; (void)retry; ASSERT (token!=NULL); openvpn_snprintf (szPrompt, sizeof (szPrompt), "%s token", token->label); token_pass.defined = false; token_pass.nocache = true; if ( !get_user_pass ( &token_pass, NULL, szPrompt, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL ) ) { return false; } else { strncpynt (szPIN, token_pass.password, nMaxPIN); purge_user_pass (&token_pass, true); if (strlen (szPIN) == 0) { return false; } else { return true; } } }
/* * Record IP/port of client in filesystem, so that server receiving * the proxy can determine true client origin. */ static void journal_add(const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp) { struct gc_arena gc = gc_new(); struct openvpn_sockaddr from, to; socklen_t slen, dlen; int fnlen; char *jfn; int fd; slen = sizeof(from.addr.sa); dlen = sizeof(to.addr.sa); if (!getpeername(pc->sd, (struct sockaddr *) &from.addr.sa, &slen) && !getsockname(cp->sd, (struct sockaddr *) &to.addr.sa, &dlen)) { const char *f = print_openvpn_sockaddr(&from, &gc); const char *t = print_openvpn_sockaddr(&to, &gc); fnlen = strlen(journal_dir) + strlen(t) + 2; jfn = (char *) malloc(fnlen); check_malloc_return(jfn); openvpn_snprintf(jfn, fnlen, "%s/%s", journal_dir, t); dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f); fd = platform_open(jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd != -1) { if (write(fd, f, strlen(f)) != strlen(f)) { msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn); } close(fd); cp->jfn = jfn; } else { msg(M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn); free(jfn); } } gc_free(&gc); }
void setenv_str_incr(struct env_set *es, const char *name, const char *value) { unsigned int counter = 1; const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */ char *tmpname = gc_malloc(tmpname_len, true, NULL); strcpy(tmpname, name); while (NULL != env_set_get(es, tmpname) && counter < 1000) { ASSERT(openvpn_snprintf(tmpname, tmpname_len, "%s_%u", name, counter)); counter++; } if (counter < 1000) { setenv_str(es, tmpname, value); } else { msg(D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name); } free(tmpname); }
int set_lladdr(const char *ifname, const char *lladdr, const struct env_set *es) { char cmd[256]; int r; if (!ifname || !lladdr) return -1; #if defined(TARGET_LINUX) #ifdef CONFIG_FEATURE_IPROUTE openvpn_snprintf (cmd, sizeof (cmd), IPROUTE_PATH " link set addr %s dev %s", lladdr, ifname); #else openvpn_snprintf (cmd, sizeof (cmd), IFCONFIG_PATH " %s hw ether %s", ifname, lladdr); #endif #elif defined(TARGET_SOLARIS) openvpn_snprintf (cmd, sizeof (cmd), IFCONFIG_PATH " %s ether %s", ifname, lladdr); #elif defined(TARGET_OPENBSD) openvpn_snprintf (cmd, sizeof (cmd), IFCONFIG_PATH " %s lladdr %s", ifname, lladdr); #elif defined(TARGET_DARWIN) openvpn_snprintf (cmd, sizeof (cmd), IFCONFIG_PATH " %s lladdr %s", ifname, lladdr); #elif defined(TARGET_FREEBSD) openvpn_snprintf (cmd, sizeof (cmd), IFCONFIG_PATH " %s ether %s", ifname, lladdr); #else msg (M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system."); return -1; #endif r = system_check (cmd, es, M_WARN, "ERROR: Unable to set link layer address."); if (r) msg (M_INFO, "TUN/TAP link layer address set to %s", lladdr); return r; }
static void plugin_init_item(struct plugin *p, const struct plugin_option *o) { struct gc_arena gc = gc_new(); bool rel = false; p->so_pathname = o->so_pathname; p->plugin_type_mask = plugin_supported_types(); #ifndef _WIN32 p->handle = NULL; /* If the plug-in filename is not an absolute path, * or beginning with '.', it should use the PLUGIN_LIBDIR * as the base directory for loading the plug-in. * * This means the following scenarios are loaded from these places: * --plugin fancyplug.so -> $PLUGIN_LIBDIR/fancyplug.so * --plugin my/fancyplug.so -> $PLUGIN_LIBDIR/my/fancyplug.so * --plugin ./fancyplug.so -> $CWD/fancyplug.so * --plugin /usr/lib/my/fancyplug.so -> /usr/lib/my/fancyplug.so * * Please note that $CWD means the directory OpenVPN is either started from * or the directory OpenVPN have changed into using --cd before --plugin * was parsed. * */ if (!platform_absolute_pathname(p->so_pathname) && p->so_pathname[0] != '.') { char full[PATH_MAX]; openvpn_snprintf(full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname); p->handle = dlopen(full, RTLD_NOW); } else { rel = !platform_absolute_pathname(p->so_pathname); p->handle = dlopen(p->so_pathname, RTLD_NOW); } if (!p->handle) { msg(M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror()); } #define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol(p->handle, (void *)&p->var, name, p->so_pathname, flags) #else /* ifndef _WIN32 */ rel = !platform_absolute_pathname(p->so_pathname); p->module = LoadLibraryW(wide_string(p->so_pathname, &gc)); if (!p->module) { msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname); } #define PLUGIN_SYM(var, name, flags) dll_resolve_symbol(p->module, (void *)&p->var, name, p->so_pathname, flags) #endif /* ifndef _WIN32 */ PLUGIN_SYM(open1, "openvpn_plugin_open_v1", 0); PLUGIN_SYM(open2, "openvpn_plugin_open_v2", 0); PLUGIN_SYM(open3, "openvpn_plugin_open_v3", 0); PLUGIN_SYM(func1, "openvpn_plugin_func_v1", 0); PLUGIN_SYM(func2, "openvpn_plugin_func_v2", 0); PLUGIN_SYM(func3, "openvpn_plugin_func_v3", 0); PLUGIN_SYM(close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED); PLUGIN_SYM(abort, "openvpn_plugin_abort_v1", 0); PLUGIN_SYM(client_constructor, "openvpn_plugin_client_constructor_v1", 0); PLUGIN_SYM(client_destructor, "openvpn_plugin_client_destructor_v1", 0); PLUGIN_SYM(min_version_required, "openvpn_plugin_min_version_required_v1", 0); PLUGIN_SYM(initialization_point, "openvpn_plugin_select_initialization_point_v1", 0); if (!p->open1 && !p->open2 && !p->open3) { msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname); } if (!p->func1 && !p->func2 && !p->func3) { msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname); } /* * Verify that we are sufficiently up-to-date to handle the plugin */ if (p->min_version_required) { const int plugin_needs_version = (*p->min_version_required)(); if (plugin_needs_version > OPENVPN_PLUGIN_VERSION) { msg(M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s", plugin_needs_version, OPENVPN_PLUGIN_VERSION, p->so_pathname); } } if (p->initialization_point) { p->requested_initialization_point = (*p->initialization_point)(); } else { p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON; } if (rel) { msg(M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname); } p->initialized = true; gc_free(&gc); }
void x_msg_va (const unsigned int flags, const char *format, va_list arglist) { struct gc_arena gc; #if SYSLOG_CAPABILITY int level; #endif char *m1; char *m2; char *tmp; int e; const char *prefix; const char *prefix_sep; void usage_small (void); #ifndef HAVE_VARARG_MACROS /* the macro has checked this otherwise */ if (!MSG_TEST (flags)) return; #endif e = openvpn_errno (); /* * Apply muting filter. */ #ifndef HAVE_VARARG_MACROS /* the macro has checked this otherwise */ if (!dont_mute (flags)) return; #endif gc_init (&gc); m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc); m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc); vsnprintf (m1, ERR_BUF_SIZE, format, arglist); m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */ if ((flags & M_ERRNO) && e) { openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s (errno=%d)", m1, strerror_ts (e, &gc), e); SWAP; } #ifdef ENABLE_CRYPTO #ifdef ENABLE_CRYPTO_OPENSSL if (flags & M_SSL) { int nerrs = 0; int err; while ((err = ERR_get_error ())) { openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s", m1, ERR_error_string (err, NULL)); SWAP; ++nerrs; } if (!nerrs) { openvpn_snprintf (m2, ERR_BUF_SIZE, "%s (OpenSSL)", m1); SWAP; } } #endif #endif if (flags & M_OPTERR) { openvpn_snprintf (m2, ERR_BUF_SIZE, "Options error: %s", m1); SWAP; } #if SYSLOG_CAPABILITY if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL)) level = LOG_ERR; else if (flags & M_WARN) level = LOG_WARNING; else level = LOG_NOTICE; #endif /* set up client prefix */ if (flags & M_NOIPREFIX) prefix = NULL; else prefix = msg_get_prefix (); prefix_sep = " "; if (!prefix) prefix_sep = prefix = ""; /* virtual output capability used to copy output to management subsystem */ if (!forked) { const struct virtual_output *vo = msg_get_virtual_output (); if (vo) { openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s", prefix, prefix_sep, m1); virtual_output_print (vo, flags, m2); } } if (!(flags & M_MSG_VIRT_OUT)) { if (use_syslog && !std_redir && !forked) { #if SYSLOG_CAPABILITY syslog (level, "%s%s%s", prefix, prefix_sep, m1); #endif } else { FILE *fp = msg_fp(flags); const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME); if ((flags & M_NOPREFIX) || suppress_timestamps) { fprintf (fp, "%s%s%s%s", prefix, prefix_sep, m1, (flags&M_NOLF) ? "" : "\n"); } else { fprintf (fp, "%s %s%s%s%s", time_string (0, 0, show_usec, &gc), prefix, prefix_sep, m1, (flags&M_NOLF) ? "" : "\n"); } fflush(fp); ++x_msg_line_num; } } if (flags & M_FATAL) msg (M_INFO, "Exiting due to fatal error"); if (flags & M_FATAL) openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ if (flags & M_USAGE_SMALL) usage_small (); gc_free (&gc); }
bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const int port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received) { struct gc_arena gc = gc_new (); char buf[512]; char buf2[128]; char get[80]; int status; int nparms; bool ret = false; bool processed = false; /* get user/pass if not previously given */ if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_DIGEST || p->auth_method == HTTP_AUTH_NTLM) get_user_pass_http (p, false); /* are we being called again after getting the digest server nonce in the previous transaction? */ if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) { nparms = 1; status = 407; } else { /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf(buf, sizeof(buf), "Host: %s", host); if (!send_line_crlf(sd, buf)) goto error; /* send User-Agent string if provided */ if (p->options.user_agent) { openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", p->options.user_agent); if (!send_line_crlf (sd, buf)) goto error; } /* auth specified? */ switch (p->auth_method) { case HTTP_AUTH_NONE: break; case HTTP_AUTH_BASIC: openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", username_password_as_base64 (p, &gc)); msg (D_PROXY, "Attempting Basic Proxy-Authorization"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; break; #if NTLM case HTTP_AUTH_NTLM: case HTTP_AUTH_NTLM2: /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", ntlm_phase_1 (p, &gc)); msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; break; #endif default: ASSERT (0); } /* send empty CR, LF */ if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); } /* check for a "407 Proxy Authentication Required" response */ while (nparms >= 1 && status == 407) { msg (D_PROXY, "Proxy requires authentication"); if (p->auth_method == HTTP_AUTH_BASIC && !processed) { processed = true; } else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ { #if NTLM /* look for the phase 2 response */ while (true) { if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); nparms = sscanf (buf, get, buf2); buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ /* check for "Proxy-Authenticate: NTLM TlRM..." */ if (nparms == 1) { /* parse buf2 */ msg (D_PROXY, "auth string: '%s'", buf2); break; } } /* if we are here then auth string was got */ msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); /* receive and discard everything else */ while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) ; /* now send the phase 3 reply */ /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); { const char *np3 = ntlm_phase_3 (p, buf2, &gc); if (!np3) { msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); goto error; } openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); } msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; /* ok so far... */ /* send empty CR, LF */ if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); processed = true; #endif } #if PROXY_DIGEST_AUTH else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) { char *pa = p->proxy_authenticate; const int method = p->auth_method; ASSERT(pa); if (method == HTTP_AUTH_DIGEST) { const char *http_method = "CONNECT"; const char *nonce_count = "00000001"; const char *qop = "auth"; const char *username = p->up.username; const char *password = p->up.password; char *opaque_kv = ""; char uri[128]; uint8_t cnonce_raw[8]; uint8_t *cnonce; HASHHEX session_key; HASHHEX response; const char *realm = get_pa_var("realm", pa, &gc); const char *nonce = get_pa_var("nonce", pa, &gc); const char *algor = get_pa_var("algorithm", pa, &gc); const char *opaque = get_pa_var("opaque", pa, &gc); /* generate a client nonce */ ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); /* build the digest response */ openvpn_snprintf (uri, sizeof(uri), "%s:%d", host, port); if (opaque) { const int len = strlen(opaque)+16; opaque_kv = gc_malloc(len, false, &gc); openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); } DigestCalcHA1(algor, username, realm, password, nonce, (char *)cnonce, session_key); DigestCalcResponse(session_key, nonce, nonce_count, (char *)cnonce, qop, http_method, uri, NULL, response); /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", http_method, uri, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; /* send digest response */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", username, realm, nonce, uri, qop, nonce_count, cnonce, response, opaque_kv ); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); processed = true; } else { msg (D_PROXY, "HTTP proxy: digest method not supported"); goto error; } } #endif else if (p->options.auth_retry) { /* figure out what kind of authentication the proxy needs */ char *pa = NULL; const int method = get_proxy_authenticate(sd, p->options.timeout, &pa, NULL, signal_received); if (method != HTTP_AUTH_NONE) { if (pa) msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) { msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); goto error; } p->auth_method = method; store_proxy_authenticate(p, pa); ret = true; goto done; } else { msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); free (pa); goto error; } } else { if (!processed) msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); goto error; } /* clear state */ if (p->options.auth_retry) clear_user_pass_http(); store_proxy_authenticate(p, NULL); } /* check return code, success = 200 */ if (nparms < 1 || status != 200) { msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 /* DEBUGGING -- show a multi-line HTTP error response */ dump_residual(sd, p->options.timeout, signal_received); #endif goto error; } /* SUCCESS */ /* receive line from proxy and discard */ if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) goto error; /* * Toss out any extraneous chars, but don't throw away the * start of the OpenVPN data stream (put it in lookahead). */ while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) ; /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ p->queried_creds = false; #if 0 if (lookahead && BLEN (lookahead)) msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); #endif done: gc_free (&gc); return ret; error: /* on error, should we exit or restart? */ if (!*signal_received) *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ gc_free (&gc); return ret; }
/* * Save X509 fields to environment, using the naming convention: * * X509_{cert_depth}_{name}={value} */ void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) { int i; unsigned char c; const x509_name *name; char s[128]; name = &cert->subject; memset( s, 0, sizeof( s ) ); while( name != NULL ) { char name_expand[64+8]; if( name->oid.len == 2 && memcmp( name->oid.p, OID_X520, 2 ) == 0 ) { switch( name->oid.p[2] ) { case X520_COMMON_NAME: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_CN", cert_depth); break; case X520_COUNTRY: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_C", cert_depth); break; case X520_LOCALITY: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_L", cert_depth); break; case X520_STATE: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_ST", cert_depth); break; case X520_ORGANIZATION: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_O", cert_depth); break; case X520_ORG_UNIT: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_OU", cert_depth); break; default: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_0x%02X", cert_depth, name->oid.p[2]); break; } } else if( name->oid.len == 8 && memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 ) { switch( name->oid.p[8] ) { case PKCS9_EMAIL: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_emailAddress", cert_depth); break; default: openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_0x%02X", cert_depth, name->oid.p[8]); break; } } else { openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?", cert_depth); } for( i = 0; i < name->val.len; i++ ) { if( i >= (int) sizeof( s ) - 1 ) break; c = name->val.p[i]; if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) s[i] = '?'; else s[i] = c; } s[i] = '\0'; /* Check both strings, set environment variable */ string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); string_mod ((char*)s, CC_PRINT, CC_CRLF, '_'); setenv_str (es, name_expand, (char*)s); name = name->next; } }
VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv) { char exe_path[MAX_PATH]; char config_dir[MAX_PATH]; char ext_string[16]; char log_dir[MAX_PATH]; char priority_string[64]; char append_string[2]; DWORD priority; bool append; ResetError (); if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000)) { MSG (M_ERR, "ReportStatusToSCMgr #1 failed"); goto finish; } /* * Create our exit event */ exit_event = create_event (EXIT_EVENT_NAME, false, false, true); if (!exit_event) { MSG (M_ERR, "CreateEvent failed"); goto finish; } /* * If exit event is already signaled, it means we were not * shut down properly. */ if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT) { MSG (M_ERR, "Exit event is already signaled -- we were not shut down properly"); goto finish; } if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000)) { MSG (M_ERR, "ReportStatusToSCMgr #2 failed"); goto finish; } /* * Read info from registry in key HKLM\SOFTWARE\OpenVPN */ { HKEY openvpn_key; LONG status; DWORD len; DWORD type; static const char error_format_str[] = "Error querying registry key of type REG_SZ: HKLM\\" REG_KEY "\\%s"; static const char error_format_dword[] = "Error querying registry key of type REG_DWORD: HKLM\\" REG_KEY "\\%s"; status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &openvpn_key); if (status != ERROR_SUCCESS) { SetLastError (status); MSG (M_SYSERR, "Registry key HKLM\\" REG_KEY " not found"); goto finish; } /* get path to openvpn.exe */ QUERY_REG_STRING ("exe_path", exe_path); /* get path to configuration directory */ QUERY_REG_STRING ("config_dir", config_dir); /* get extension on configuration files */ QUERY_REG_STRING ("config_ext", ext_string); /* get path to log directory */ QUERY_REG_STRING ("log_dir", log_dir); /* get priority for spawned OpenVPN subprocesses */ QUERY_REG_STRING ("priority", priority_string); /* should we truncate or append to logfile? */ QUERY_REG_STRING ("log_append", append_string); RegCloseKey (openvpn_key); } /* set process priority */ priority = NORMAL_PRIORITY_CLASS; if (!strcasecmp (priority_string, "IDLE_PRIORITY_CLASS")) priority = IDLE_PRIORITY_CLASS; else if (!strcasecmp (priority_string, "BELOW_NORMAL_PRIORITY_CLASS")) priority = BELOW_NORMAL_PRIORITY_CLASS; else if (!strcasecmp (priority_string, "NORMAL_PRIORITY_CLASS")) priority = NORMAL_PRIORITY_CLASS; else if (!strcasecmp (priority_string, "ABOVE_NORMAL_PRIORITY_CLASS")) priority = ABOVE_NORMAL_PRIORITY_CLASS; else if (!strcasecmp (priority_string, "HIGH_PRIORITY_CLASS")) priority = HIGH_PRIORITY_CLASS; else { MSG (M_ERR, "Unknown priority name: %s", priority_string); goto finish; } /* set log file append/truncate flag */ append = false; if (append_string[0] == '0') append = false; else if (append_string[0] == '1') append = true; else { MSG (M_ERR, "Log file append flag (given as '%s') must be '0' or '1'", append_string); goto finish; } /* * Instantiate an OpenVPN process for each configuration * file found. */ { WIN32_FIND_DATA find_obj; HANDLE find_handle; BOOL more_files; char find_string[MAX_PATH]; openvpn_snprintf (find_string, MAX_PATH, "%s\\*", config_dir); find_handle = FindFirstFile (find_string, &find_obj); if (find_handle == INVALID_HANDLE_VALUE) { MSG (M_ERR, "Cannot get configuration file list using: %s", find_string); goto finish; } /* * Loop over each config file */ do { HANDLE log_handle = NULL; STARTUPINFO start_info; PROCESS_INFORMATION proc_info; struct security_attributes sa; char log_file[MAX_PATH]; char log_path[MAX_PATH]; char command_line[256]; CLEAR (start_info); CLEAR (proc_info); CLEAR (sa); if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000)) { MSG (M_ERR, "ReportStatusToSCMgr #3 failed"); FindClose (find_handle); goto finish; } /* does file have the correct type and extension? */ if (match (&find_obj, ext_string)) { /* get log file pathname */ if (!modext (log_file, sizeof (log_file), find_obj.cFileName, "log")) { MSG (M_ERR, "Cannot construct logfile name based on: %s", find_obj.cFileName); FindClose (find_handle); goto finish; } openvpn_snprintf (log_path, sizeof(log_path), "%s\\%s", log_dir, log_file); /* construct command line */ openvpn_snprintf (command_line, sizeof(command_line), PACKAGE " --service %s 1 --config \"%s\"", EXIT_EVENT_NAME, find_obj.cFileName); /* Make security attributes struct for logfile handle so it can be inherited. */ if (!init_security_attributes_allow_all (&sa)) { MSG (M_SYSERR, "InitializeSecurityDescriptor start_" PACKAGE " failed"); goto finish; } /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */ log_handle = CreateFile (log_path, GENERIC_WRITE, FILE_SHARE_READ, &sa.sa, append ? OPEN_ALWAYS : CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (log_handle == INVALID_HANDLE_VALUE) { MSG (M_SYSERR, "Cannot open logfile: %s", log_path); FindClose (find_handle); goto finish; } /* append to logfile? */ if (append) { if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) { MSG (M_SYSERR, "Cannot seek to end of logfile: %s", log_path); FindClose (find_handle); goto finish; } } /* fill in STARTUPINFO struct */ GetStartupInfo(&start_info); start_info.cb = sizeof(start_info); start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; start_info.wShowWindow = SW_HIDE; start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); start_info.hStdOutput = start_info.hStdError = log_handle; /* create an OpenVPN process for one config file */ if (!CreateProcess(exe_path, command_line, NULL, NULL, TRUE, priority | CREATE_NEW_CONSOLE, NULL, config_dir, &start_info, &proc_info)) { MSG (M_SYSERR, "CreateProcess failed, exe='%s' cmdline='%s' dir='%s'", exe_path, command_line, config_dir); FindClose (find_handle); CloseHandle (log_handle); goto finish; } /* close unneeded handles */ Sleep (1000); /* try to prevent race if we close logfile handle before child process DUPs it */ if (!CloseHandle (proc_info.hProcess) || !CloseHandle (proc_info.hThread) || !CloseHandle (log_handle)) { MSG (M_SYSERR, "CloseHandle failed"); goto finish; } } /* more files to process? */ more_files = FindNextFile (find_handle, &find_obj); } while (more_files); FindClose (find_handle); } /* we are now fully started */ if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0)) { MSG (M_ERR, "ReportStatusToSCMgr SERVICE_RUNNING failed"); goto finish; } /* wait for our shutdown signal */ if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0) { MSG (M_ERR, "wait for shutdown signal failed"); } finish: ServiceStop (); if (exit_event) CloseHandle (exit_event); }
int tls_ctx_use_pkcs11( struct tls_root_ctx *const ssl_ctx, bool pkcs11_id_management, const char *const pkcs11_id ) { pkcs11h_certificate_id_t certificate_id = NULL; pkcs11h_certificate_t certificate = NULL; CK_RV rv = CKR_OK; bool ok = false; ASSERT(ssl_ctx!=NULL); ASSERT(pkcs11_id_management || pkcs11_id!=NULL); dmsg( D_PKCS11_DEBUG, "PKCS#11: tls_ctx_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'", (void *)ssl_ctx, pkcs11_id_management ? 1 : 0, pkcs11_id ); if (pkcs11_id_management) { struct user_pass id_resp; CLEAR(id_resp); id_resp.defined = false; id_resp.nocache = true; openvpn_snprintf( id_resp.username, sizeof(id_resp.username), "Please specify PKCS#11 id to use" ); if ( !get_user_pass( &id_resp, NULL, "pkcs11-id-request", GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_STR|GET_USER_PASS_NOFATAL ) ) { goto cleanup; } if ( (rv = pkcs11h_certificate_deserializeCertificateId( &certificate_id, id_resp.password )) != CKR_OK ) { msg(M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; } } else { if ( (rv = pkcs11h_certificate_deserializeCertificateId( &certificate_id, pkcs11_id )) != CKR_OK ) { msg(M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; } } if ( (rv = pkcs11h_certificate_create( certificate_id, NULL, PKCS11H_PROMPT_MASK_ALLOW_ALL, PKCS11H_PIN_CACHE_INFINITE, &certificate )) != CKR_OK ) { msg(M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage(rv)); goto cleanup; } if ( (pkcs11_init_tls_session( certificate, ssl_ctx )) ) { /* Handled by SSL context free */ certificate = NULL; goto cleanup; } /* Handled by SSL context free */ certificate = NULL; ok = true; cleanup: if (certificate != NULL) { pkcs11h_certificate_freeCertificate(certificate); certificate = NULL; } if (certificate_id != NULL) { pkcs11h_certificate_freeCertificateId(certificate_id); certificate_id = NULL; } dmsg( D_PKCS11_DEBUG, "PKCS#11: tls_ctx_use_pkcs11 - return ok=%d, rv=%ld", ok ? 1 : 0, rv ); return ok ? 1 : 0; }
bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const int port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received) { struct gc_arena gc = gc_new (); char buf[256]; char buf2[128]; char get[80]; int status; int nparms; bool ret = false; /* get user/pass if not previously given or if --auto-proxy is being used */ if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM) get_user_pass_http (p, false); /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s\r\nHOST: %s:%d", host, port, p->options.http_version, host, port); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* send User-Agent string if provided */ if (p->options.user_agent) { openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", p->options.user_agent); if (!send_line_crlf (sd, buf)) goto error; } /* auth specified? */ switch (p->auth_method) { case HTTP_AUTH_NONE: break; case HTTP_AUTH_BASIC: openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", username_password_as_base64 (p, &gc)); msg (D_PROXY, "Attempting Basic Proxy-Authorization"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); openvpn_sleep (1); if (!send_line_crlf (sd, buf)) goto error; break; #if NTLM case HTTP_AUTH_NTLM: case HTTP_AUTH_NTLM2: /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", ntlm_phase_1 (p, &gc)); msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); openvpn_sleep (1); if (!send_line_crlf (sd, buf)) goto error; break; #endif default: ASSERT (0); } /* send empty CR, LF */ openvpn_sleep (1); if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); /* check for a "407 Proxy Authentication Required" response */ if (nparms >= 1 && status == 407) { msg (D_PROXY, "Proxy requires authentication"); /* check for NTLM */ if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) { #if NTLM /* look for the phase 2 response */ while (true) { if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); nparms = sscanf (buf, get, buf2); buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ /* check for "Proxy-Authenticate: NTLM TlRM..." */ if (nparms == 1) { /* parse buf2 */ msg (D_PROXY, "auth string: '%s'", buf2); break; } } /* if we are here then auth string was got */ msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); /* receive and discard everything else */ while (recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) ; /* now send the phase 3 reply */ /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_sleep (1); openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); { const char *np3 = ntlm_phase_3 (p, buf2, &gc); if (!np3) { msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); goto error; } openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); } msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); openvpn_sleep (1); if (!send_line_crlf (sd, buf)) goto error; /* ok so far... */ /* send empty CR, LF */ openvpn_sleep (1); if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); #else ASSERT (0); /* No NTLM support */ #endif } else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry) { /* * Proxy needs authentication, but we don't have a user/pass. * Now we will change p->auth_method and return true so that * our caller knows to call us again on a newly opened socket. * JYFIXME: This code needs to check proxy error output and set * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary. */ p->auth_method = HTTP_AUTH_BASIC; ret = true; goto done; } else goto error; } /* check return code, success = 200 */ if (nparms < 1 || status != 200) { msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 /* DEBUGGING -- show a multi-line HTTP error response */ while (true) { if (!recv_line (sd, buf, sizeof (buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); } #endif goto error; } /* receive line from proxy and discard */ if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) goto error; /* * Toss out any extraneous chars, but don't throw away the * start of the OpenVPN data stream (put it in lookahead). */ while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) ; #if 0 if (lookahead && BLEN (lookahead)) msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); #endif done: gc_free (&gc); return ret; error: /* on error, should we exit or restart? */ if (!*signal_received) *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ gc_free (&gc); return ret; }
static void plugin_init_item (struct plugin *p, const struct plugin_option *o) { struct gc_arena gc = gc_new (); bool rel = false; p->so_pathname = o->so_pathname; p->plugin_type_mask = plugin_supported_types (); #if defined(USE_LIBDL) p->handle = NULL; #if defined(PLUGIN_LIBDIR) if (!absolute_pathname (p->so_pathname)) { char full[PATH_MAX]; openvpn_snprintf (full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname); p->handle = dlopen (full, RTLD_NOW); #if defined(ENABLE_PLUGIN_SEARCH) if (!p->handle) { rel = true; p->handle = dlopen (p->so_pathname, RTLD_NOW); } #endif } else #endif { rel = !absolute_pathname (p->so_pathname); p->handle = dlopen (p->so_pathname, RTLD_NOW); } if (!p->handle) msg (M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror()); # define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol (p->handle, (void*)&p->var, name, p->so_pathname, flags) #elif defined(USE_LOAD_LIBRARY) rel = !absolute_pathname (p->so_pathname); p->module = LoadLibrary (p->so_pathname); if (!p->module) msg (M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname); # define PLUGIN_SYM(var, name, flags) dll_resolve_symbol (p->module, (void*)&p->var, name, p->so_pathname, flags) #endif PLUGIN_SYM (open1, "openvpn_plugin_open_v1", 0); PLUGIN_SYM (open2, "openvpn_plugin_open_v2", 0); PLUGIN_SYM (open3, "openvpn_plugin_open_v3", 0); PLUGIN_SYM (func1, "openvpn_plugin_func_v1", 0); PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0); PLUGIN_SYM (func3, "openvpn_plugin_func_v3", 0); PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED); PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0); PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0); PLUGIN_SYM (client_destructor, "openvpn_plugin_client_destructor_v1", 0); PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0); PLUGIN_SYM (initialization_point, "openvpn_plugin_select_initialization_point_v1", 0); if (!p->open1 && !p->open2 && !p->open3) msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname); if (!p->func1 && !p->func2 && !p->func3) msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname); /* * Verify that we are sufficiently up-to-date to handle the plugin */ if (p->min_version_required) { const int plugin_needs_version = (*p->min_version_required)(); if (plugin_needs_version > OPENVPN_PLUGIN_VERSION) msg (M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s", plugin_needs_version, OPENVPN_PLUGIN_VERSION, p->so_pathname); } if (p->initialization_point) p->requested_initialization_point = (*p->initialization_point)(); else p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON; if (rel) msg (M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname); p->initialized = true; gc_free (&gc); }
void ifconfig_pool_test(in_addr_t start, in_addr_t end) { struct gc_arena gc = gc_new(); struct ifconfig_pool *p = ifconfig_pool_init(IFCONFIG_POOL_30NET, start, end); /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/ ifconfig_pool_handle array[256]; int i; CLEAR(array); msg(M_INFO | M_NOPREFIX, "************ 1"); for (i = 0; i < (int) SIZE(array); ++i) { char *cn; ifconfig_pool_handle h; in_addr_t local, remote; char buf[256]; openvpn_snprintf(buf, sizeof(buf), "common-name-%d", i); #ifdef DUP_CN cn = NULL; #else cn = buf; #endif h = ifconfig_pool_acquire(p, &local, &remote, NULL, cn); if (h < 0) { break; } msg(M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s", print_in_addr_t(local, 0, &gc), print_in_addr_t(remote, 0, &gc), cn); array[i] = h; } msg(M_INFO | M_NOPREFIX, "************* 2"); for (i = (int) SIZE(array) / 16; i < (int) SIZE(array) / 8; ++i) { msg(M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name); if (!ifconfig_pool_release(p, array[i])) { break; } msg(M_INFO, "Succeeded"); } CLEAR(array); msg(M_INFO | M_NOPREFIX, "**************** 3"); for (i = 0; i < (int) SIZE(array); ++i) { char *cn; ifconfig_pool_handle h; in_addr_t local, remote; char buf[256]; snprintf(buf, sizeof(buf), "common-name-%d", i+24); #ifdef DUP_CN cn = NULL; #else cn = buf; #endif h = ifconfig_pool_acquire(p, &local, &remote, NULL, cn); if (h < 0) { break; } msg(M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s", print_in_addr_t(local, 0, &gc), print_in_addr_t(remote, 0, &gc), cn); array[i] = h; } ifconfig_pool_free(p); gc_free(&gc); }