/*
 * 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
/*
 * Handle incoming configuration
 * messages on the control channel.
 */
void
check_incoming_control_channel_dowork (struct context *c)
{
  const int len = tls_test_payload_len (c->c2.tls_multi);
  if (len)
    {
      struct gc_arena gc = gc_new ();
      struct buffer buf = alloc_buf_gc (len, &gc);
      if (tls_rec_payload (c->c2.tls_multi, &buf))
	{
	  /* force null termination of message */
	  buf_null_terminate (&buf);

	  /* enforce character class restrictions */
	  string_mod (BSTR (&buf), CC_PRINT, CC_CRLF, 0);

	  if (buf_string_match_head_str (&buf, "AUTH_FAILED"))
	    receive_auth_failed (c, &buf);
	  else if (buf_string_match_head_str (&buf, "PUSH_"))
	    incoming_push_message (c, &buf);
	  else if (buf_string_match_head_str (&buf, "RESTART"))
	    server_pushed_signal (c, &buf, true, 7);
	  else if (buf_string_match_head_str (&buf, "HALT"))
	    server_pushed_signal (c, &buf, false, 4);
	  else
	    msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf));
	}
      else
	{
	  msg (D_PUSH_ERRORS, "WARNING: Receive control message failed");
	}

      gc_free (&gc);
    }
}
示例#3
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);
    }
}
示例#4
0
void
character_class_debug (void)
{
  char buf[256];

  while (fgets (buf, sizeof (buf), stdin) != NULL)
    {
      string_mod (buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE);
      printf ("%s", buf);
    }
}
示例#5
0
文件: win32.c 项目: benjdag/openvpn
static WCHAR *
wide_cmd_line(const struct argv *a, struct gc_arena *gc)
{
    size_t nchars = 1;
    size_t maxlen = 0;
    size_t i;
    struct buffer buf;
    char *work = NULL;

    if (!a)
    {
        return NULL;
    }

    for (i = 0; i < a->argc; ++i)
    {
        const char *arg = a->argv[i];
        const size_t len = strlen(arg);
        nchars += len + 3;
        if (len > maxlen)
        {
            maxlen = len;
        }
    }

    work = gc_malloc(maxlen + 1, false, gc);
    check_malloc_return(work);
    buf = alloc_buf_gc(nchars, gc);

    for (i = 0; i < a->argc; ++i)
    {
        const char *arg = a->argv[i];
        strcpy(work, arg);
        string_mod(work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_');
        if (i)
        {
            buf_printf(&buf, " ");
        }
        if (string_class(work, CC_ANY, CC_SPACE))
        {
            buf_printf(&buf, "%s", work);
        }
        else
        {
            buf_printf(&buf, "\"%s\"", work);
        }
    }

    return wide_string(BSTR(&buf), gc);
}
示例#6
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);
}
示例#7
0
const char *
string_mod_const (const char *str,
		  const unsigned int inclusive,
		  const unsigned int exclusive,
		  const char replace,
		  struct gc_arena *gc)
{
  if (str)
    {
      char *buf = string_alloc (str, gc);
      string_mod (buf, inclusive, exclusive, replace);
      return buf;
    }
  else
    return NULL;
}
示例#8
0
static char *
cmd_line (const struct argv *a)
{
  size_t nchars = 1;
  size_t maxlen = 0;
  size_t i;
  struct buffer buf;
  char *work = NULL;

  if (!a)
    return NULL;

  for (i = 0; i < a->argc; ++i)
    {
      const char *arg = a->argv[i];
      const size_t len = strlen (arg);
      nchars += len + 3;
      if (len > maxlen)
	maxlen = len;
    }

  work = (char *) malloc (maxlen + 1);
  check_malloc_return (work);
  buf = alloc_buf (nchars);

  for (i = 0; i < a->argc; ++i)
    {
      const char *arg = a->argv[i];
      strcpy (work, arg);
      string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_');
      if (i)
	buf_printf (&buf, " ");
      if (string_class (work, CC_ANY, CC_SPACE))
	buf_printf (&buf, "%s", work);
      else
	buf_printf (&buf, "\"%s\"", work);
    }

  free (work);
  return BSTR(&buf);
}
示例#9
0
bool
get_user_pass_cr (struct user_pass *up,
		  const char *auth_file,
		  const char *prefix,
		  const unsigned int flags,
		  const char *auth_challenge)
{
  struct gc_arena gc = gc_new ();

  if (!up->defined)
    {
      const bool from_stdin = (!auth_file || !strcmp (auth_file, "stdin"));

      if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
	msg (M_WARN, "Note: previous '%s' credentials failed", prefix);

#ifdef ENABLE_MANAGEMENT
      /*
       * Get username/password from management interface?
       */
      if (management
	  && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT)))
	  && management_query_user_pass_enabled (management))
	{
	  const char *sc = NULL;

	  if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
	    management_auth_failure (management, prefix, "previous auth credentials failed");

#ifdef ENABLE_CLIENT_CR
	  if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE))
	    sc = auth_challenge;
#endif
	  if (!management_query_user_pass (management, up, prefix, flags, sc))
	    {
	      if ((flags & GET_USER_PASS_NOFATAL) != 0)
		return false;
	      else
		msg (M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix);
	    }
	}
      else
#endif
      /*
       * Get NEED_OK confirmation from the console
       */
      if (flags & GET_USER_PASS_NEED_OK)
	{
	  struct buffer user_prompt = alloc_buf_gc (128, &gc);

	  buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username);
	  
	  if (!get_console_input (BSTR (&user_prompt), true, up->password, USER_PASS_LEN))
	    msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
	  
	  if (!strlen (up->password))
	    strcpy (up->password, "ok");
	}
	  
      /*
       * Get username/password from standard input?
       */
      else if (from_stdin)
	{
#ifndef WIN32
	  /* did we --daemon'ize before asking for passwords? */
	  if ( !isatty(0) && !isatty(2) )
	    { msg(M_FATAL, "neither stdin nor stderr are a tty device, can't ask for %s password.  If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prefix ); }
#endif

#ifdef ENABLE_CLIENT_CR
	  if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE))
	    {
	      struct auth_challenge_info *ac = get_auth_challenge (auth_challenge, &gc);
	      if (ac)
		{
		  char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
		  struct buffer packed_resp;

		  buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN);
		  msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", ac->challenge_text);
		  if (!get_console_input ("Response:", BOOL_CAST(ac->flags&CR_ECHO), response, USER_PASS_LEN))
		    msg (M_FATAL, "ERROR: could not read challenge response from stdin");
		  strncpynt (up->username, ac->user, USER_PASS_LEN);
		  buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response);
		}
	      else
		{
		  msg (M_FATAL, "ERROR: received malformed challenge request from server");
		}
	    }
	  else
#endif
	    {
	      struct buffer user_prompt = alloc_buf_gc (128, &gc);
	      struct buffer pass_prompt = alloc_buf_gc (128, &gc);

	      buf_printf (&user_prompt, "Enter %s Username:"******"Enter %s Password:"******"ERROR: could not read %s username from stdin", prefix);
		  if (strlen (up->username) == 0)
		    msg (M_FATAL, "ERROR: %s username is empty", prefix);
		}

	      if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
		msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);

#ifdef ENABLE_CLIENT_CR
	      if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE))
		{
		  char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
		  struct buffer packed_resp;
		  char *pw64=NULL, *resp64=NULL;

		  msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", auth_challenge);
		  if (!get_console_input ("Response:", BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), response, USER_PASS_LEN))
		    msg (M_FATAL, "ERROR: could not read static challenge response from stdin");
		  if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1
		      || openvpn_base64_encode(response, strlen(response), &resp64) == -1)
		    msg (M_FATAL, "ERROR: could not base64-encode password/static_response");
		  buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN);
		  buf_printf (&packed_resp, "SCRV1:%s:%s", pw64, resp64);
		  string_clear(pw64);
		  free(pw64);
		  string_clear(resp64);
		  free(resp64);
		}
#endif
	    }
	}
      else
	{
	  /*
	   * Get username/password from a file.
	   */
	  FILE *fp;
      
#ifndef ENABLE_PASSWORD_SAVE
	  /*
	   * Unless ENABLE_PASSWORD_SAVE is defined, don't allow sensitive passwords
	   * to be read from a file.
	   */
	  if (flags & GET_USER_PASS_SENSITIVE)
	    msg (M_FATAL, "Sorry, '%s' password cannot be read from a file", prefix);
#endif

	  warn_if_group_others_accessible (auth_file);

	  fp = platform_fopen (auth_file, "r");
	  if (!fp)
	    msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file);

	  if (flags & GET_USER_PASS_PASSWORD_ONLY)
	    {
	      if (fgets (up->password, USER_PASS_LEN, fp) == NULL)
		msg (M_FATAL, "Error reading password from %s authfile: %s",
		     prefix,
		     auth_file);
	    }
	  else
	    {
	      if (fgets (up->username, USER_PASS_LEN, fp) == NULL
		  || fgets (up->password, USER_PASS_LEN, fp) == NULL)
		msg (M_FATAL, "Error reading username and password (must be on two consecutive lines) from %s authfile: %s",
		     prefix,
		     auth_file);
	    }
      
	  fclose (fp);
      
	  chomp (up->username);
	  chomp (up->password);
      
	  if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0)
	    msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file);
	}

      string_mod (up->username, CC_PRINT, CC_CRLF, 0);
      string_mod (up->password, CC_PRINT, CC_CRLF, 0);

      up->defined = true;
    }

#if 0
  msg (M_INFO, "GET_USER_PASS %s u='%s' p='%s'", prefix, up->username, up->password);
#endif

  gc_free (&gc);

  return true;
}
示例#10
0
文件: misc.c 项目: anlaneg/openvpn
bool
get_user_pass_cr(struct user_pass *up,
                 const char *auth_file,
                 const char *prefix,
                 const unsigned int flags,
                 const char *auth_challenge)
{
    struct gc_arena gc = gc_new();

    if (!up->defined)
    {
        bool from_authfile = (auth_file && !streq(auth_file, "stdin"));
        bool username_from_stdin = false;
        bool password_from_stdin = false;
        bool response_from_stdin = true;

        if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
        {
            msg(M_WARN, "Note: previous '%s' credentials failed", prefix);
        }

#ifdef ENABLE_MANAGEMENT
        /*
         * Get username/password from management interface?
         */
        if (management
            && (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT))
            && management_query_user_pass_enabled(management))
        {
            const char *sc = NULL;
            response_from_stdin = false;

            if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
            {
                management_auth_failure(management, prefix, "previous auth credentials failed");
            }

#ifdef ENABLE_CLIENT_CR
            if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE))
            {
                sc = auth_challenge;
            }
#endif
            if (!management_query_user_pass(management, up, prefix, flags, sc))
            {
                if ((flags & GET_USER_PASS_NOFATAL) != 0)
                {
                    return false;
                }
                else
                {
                    msg(M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix);
                }
            }
        }
        else
#endif /* ifdef ENABLE_MANAGEMENT */
        /*
         * Get NEED_OK confirmation from the console
         */
        if (flags & GET_USER_PASS_NEED_OK)
        {
            struct buffer user_prompt = alloc_buf_gc(128, &gc);

            buf_printf(&user_prompt, "NEED-OK|%s|%s:", prefix, up->username);
            if (!query_user_SINGLE(BSTR(&user_prompt), BLEN(&user_prompt),
                                   up->password, USER_PASS_LEN, false))
            {
                msg(M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
            }

            if (!strlen(up->password))
            {
                strcpy(up->password, "ok");
            }
        }
        else if (flags & GET_USER_PASS_INLINE_CREDS)
        {
            struct buffer buf;
            buf_set_read(&buf, (uint8_t *) auth_file, strlen(auth_file) + 1);
            if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
            {
                buf_parse(&buf, '\n', up->username, USER_PASS_LEN);
            }
            buf_parse(&buf, '\n', up->password, USER_PASS_LEN);
        }
        /*
         * Read from auth file unless this is a dynamic challenge request.
         */
        else if (from_authfile && !(flags & GET_USER_PASS_DYNAMIC_CHALLENGE))
        {
            /*
             * Try to get username/password from a file.
             */
            FILE *fp;
            char password_buf[USER_PASS_LEN] = { '\0' };

            fp = platform_fopen(auth_file, "r");
            if (!fp)
            {
                msg(M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file);
            }

            if ((flags & GET_USER_PASS_PASSWORD_ONLY) == 0)
            {
                /* Read username first */
                if (fgets(up->username, USER_PASS_LEN, fp) == NULL)
                {
                    msg(M_FATAL, "Error reading username from %s authfile: %s",
                        prefix,
                        auth_file);
                }
            }
            chomp(up->username);

            if (fgets(password_buf, USER_PASS_LEN, fp) != NULL)
            {
                chomp(password_buf);
            }

            if (flags & GET_USER_PASS_PASSWORD_ONLY && !password_buf[0])
            {
                msg(M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file);
            }

            if (password_buf[0])
            {
                strncpy(up->password, password_buf, USER_PASS_LEN);
            }
            else
            {
                password_from_stdin = 1;
            }

            fclose(fp);

            if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen(up->username) == 0)
            {
                msg(M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file);
            }
        }
        else
        {
            username_from_stdin = true;
            password_from_stdin = true;
        }

        /*
         * Get username/password from standard input?
         */
        if (username_from_stdin || password_from_stdin || response_from_stdin)
        {
#ifdef ENABLE_CLIENT_CR
            if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE) && response_from_stdin)
            {
                struct auth_challenge_info *ac = get_auth_challenge(auth_challenge, &gc);
                if (ac)
                {
                    char *response = (char *) gc_malloc(USER_PASS_LEN, false, &gc);
                    struct buffer packed_resp, challenge;

                    challenge = alloc_buf_gc(14+strlen(ac->challenge_text), &gc);
                    buf_printf(&challenge, "CHALLENGE: %s", ac->challenge_text);
                    buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN);

                    if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge),
                                           response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO)))
                    {
                        msg(M_FATAL, "ERROR: could not read challenge response from stdin");
                    }
                    strncpynt(up->username, ac->user, USER_PASS_LEN);
                    buf_printf(&packed_resp, "CRV1::%s::%s", ac->state_id, response);
                }
                else
                {
                    msg(M_FATAL, "ERROR: received malformed challenge request from server");
                }
            }
            else
#endif /* ifdef ENABLE_CLIENT_CR */
            {
                struct buffer user_prompt = alloc_buf_gc(128, &gc);
                struct buffer pass_prompt = alloc_buf_gc(128, &gc);

                query_user_clear();
                buf_printf(&user_prompt, "Enter %s Username:"******"Enter %s Password:"******"ERROR: Failed retrieving username or password");
                }

                if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
                {
                    if (strlen(up->username) == 0)
                    {
                        msg(M_FATAL, "ERROR: %s username is empty", prefix);
                    }
                }

#ifdef ENABLE_CLIENT_CR
                if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin)
                {
                    char *response = (char *) gc_malloc(USER_PASS_LEN, false, &gc);
                    struct buffer packed_resp, challenge;
                    char *pw64 = NULL, *resp64 = NULL;

                    challenge = alloc_buf_gc(14+strlen(auth_challenge), &gc);
                    buf_printf(&challenge, "CHALLENGE: %s", auth_challenge);

                    if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge),
                                           response, USER_PASS_LEN,
                                           BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO)))
                    {
                        msg(M_FATAL, "ERROR: could not retrieve static challenge response");
                    }
                    if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1
                        || openvpn_base64_encode(response, strlen(response), &resp64) == -1)
                    {
                        msg(M_FATAL, "ERROR: could not base64-encode password/static_response");
                    }
                    buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN);
                    buf_printf(&packed_resp, "SCRV1:%s:%s", pw64, resp64);
                    string_clear(pw64);
                    free(pw64);
                    string_clear(resp64);
                    free(resp64);
                }
#endif /* ifdef ENABLE_CLIENT_CR */
            }
        }

        string_mod(up->username, CC_PRINT, CC_CRLF, 0);
        string_mod(up->password, CC_PRINT, CC_CRLF, 0);

        up->defined = true;
    }

#if 0
    msg(M_INFO, "GET_USER_PASS %s u='%s' p='%s'", prefix, up->username, up->password);
#endif

    gc_free(&gc);

    return true;
}
示例#11
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;
    }
}