Пример #1
0
/*
 * 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;
    }
}
Пример #2
0
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);
}
Пример #3
0
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);
}
Пример #4
0
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;
    }
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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;
}
Пример #8
0
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);
    }
}
Пример #9
0
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);
}
Пример #10
0
/* **************************************
 *
 * 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);
}
Пример #11
0
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;
        }
    }
}
Пример #12
0
/* 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);
}
Пример #13
0
/*
 * 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);
    }
}
Пример #14
0
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;
    }
}
Пример #15
0
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;
    }
}
Пример #16
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;
		}
	}
}
Пример #17
0
/*
 * 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);
}
Пример #18
0
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);
}
Пример #19
0
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;
}
Пример #20
0
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);
}
Пример #21
0
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);
}
Пример #22
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[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;
}
Пример #23
0
/*
 * 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;
    }
}
Пример #24
0
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);
}
Пример #25
0
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;
}
Пример #26
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;
}
Пример #27
0
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);
}
Пример #28
0
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);
}