コード例 #1
0
ファイル: misc.c プロジェクト: huamichaelchen/openvpn
/* create a temporary filename in directory */
const char *
create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc)
{
  static unsigned int counter;
  struct buffer fname = alloc_buf_gc (256, gc);
  int fd;
  const char *retfname = NULL;
  unsigned int attempts = 0;

  do
    {
      uint8_t rndbytes[16];
      const char *rndstr;

      ++attempts;
      ++counter;

      prng_bytes (rndbytes, sizeof rndbytes);
      rndstr = format_hex_ex (rndbytes, sizeof rndbytes, 40, 0, NULL, gc);
      buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr);

      retfname = gen_path (directory, BSTR (&fname), gc);
      if (!retfname)
        {
          msg (M_FATAL, "Failed to create temporary filename and path");
          return NULL;
        }

      /* Atomically create the file.  Errors out if the file already
         exists.  */
      fd = platform_open (retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
      if (fd != -1)
        {
          close (fd);
          return retfname;
        }
      else if (fd == -1 && errno != EEXIST)
        {
          /* Something else went wrong, no need to retry.  */
          struct gc_arena gcerr = gc_new ();
          msg (M_FATAL, "Could not create temporary file '%s': %s",
               retfname, strerror_ts (errno, &gcerr));
          gc_free (&gcerr);
          return NULL;
        }
    }
  while (attempts < 6);

  msg (M_FATAL, "Failed to create temporary file after %i attempts", attempts);
  return NULL;
}
コード例 #2
0
int
read_passphrase_hash (const char *passphrase_file,
		      const md_kt_t *digest,
		      uint8_t *output,
		      int len)
{
  unsigned int outlen = 0;
  md_ctx_t md;

  ASSERT (len >= md_kt_size(digest));
  memset (output, 0, len);

  md_ctx_init(&md, digest);

  /* read passphrase file */
  {
    const int min_passphrase_size = 8;
    uint8_t buf[64];
    int total_size = 0;
    int fd = platform_open (passphrase_file, O_RDONLY, 0);

    if (fd == -1)
      msg (M_ERR, "Cannot open passphrase file: '%s'", passphrase_file);

    for (;;)
      {
	int size = read (fd, buf, sizeof (buf));
	if (size == 0)
	  break;
	if (size == -1)
	  msg (M_ERR, "Read error on passphrase file: '%s'",
	       passphrase_file);
	md_ctx_update(&md, buf, size);
	total_size += size;
      }
    close (fd);

    warn_if_group_others_accessible (passphrase_file);

    if (total_size < min_passphrase_size)
      msg (M_FATAL,
	   "Passphrase file '%s' is too small (must have at least %d characters)",
	   passphrase_file, min_passphrase_size);
  }
  md_ctx_final(&md, output);
  md_ctx_cleanup(&md);
  return md_kt_size(digest);
}
コード例 #3
0
ファイル: ps.c プロジェクト: OpenVPN/openvpn
/*
 * 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);
}
コード例 #4
0
void
read_key_file (struct key2 *key2, const char *file, const unsigned int flags)
{
  struct gc_arena gc = gc_new ();
  struct buffer in;
  int fd, size;
  uint8_t hex_byte[3] = {0, 0, 0};
  const char *error_filename = file;

  /* parse info */
  const unsigned char *cp;
  int hb_index = 0;
  int line_num = 1;
  int line_index = 0;
  int match = 0;

  /* output */
  uint8_t* out = (uint8_t*) &key2->keys;
  const int keylen = sizeof (key2->keys);
  int count = 0;

  /* parse states */
# define PARSE_INITIAL        0
# define PARSE_HEAD           1
# define PARSE_DATA           2
# define PARSE_DATA_COMPLETE  3
# define PARSE_FOOT           4
# define PARSE_FINISHED       5
  int state = PARSE_INITIAL;

  /* constants */
  const int hlen = strlen (static_key_head);
  const int flen = strlen (static_key_foot);
  const int onekeylen = sizeof (key2->keys[0]);

  CLEAR (*key2);

  /*
   * Key can be provided as a filename in 'file' or if RKF_INLINE
   * is set, the actual key data itself in ascii form.
   */
  if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */
    {
      size = strlen (file) + 1;
      buf_set_read (&in, (const uint8_t *)file, size);
      error_filename = INLINE_FILE_TAG;
    }
  else /* 'file' is a filename which refers to a file containing the ascii key */
    {
      in = alloc_buf_gc (2048, &gc);
      fd = platform_open (file, O_RDONLY, 0);
      if (fd == -1)
	msg (M_ERR, "Cannot open file key file '%s'", file);
      size = read (fd, in.data, in.capacity);
      if (size < 0)
	msg (M_FATAL, "Read error on key file ('%s')", file);
      if (size == in.capacity)
	msg (M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity);
      close (fd);
    }

  cp = (unsigned char *)in.data;
  while (size > 0)
    {
      const unsigned char c = *cp;

#if 0
      msg (M_INFO, "char='%c'[%d] s=%d ln=%d li=%d m=%d c=%d",
	   c, (int)c, state, line_num, line_index, match, count);
#endif

      if (c == '\n')
	{
	  line_index = match = 0;
	  ++line_num;	      
	}
      else
	{
	  /* first char of new line */
	  if (!line_index)
	    {
	      /* first char of line after header line? */
	      if (state == PARSE_HEAD)
		state = PARSE_DATA;

	      /* first char of footer */
	      if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-')
		state = PARSE_FOOT;
	    }

	  /* compare read chars with header line */
	  if (state == PARSE_INITIAL)
	    {
	      if (line_index < hlen && c == static_key_head[line_index])
		{
		  if (++match == hlen)
		    state = PARSE_HEAD;
		}
	    }

	  /* compare read chars with footer line */
	  if (state == PARSE_FOOT)
	    {
	      if (line_index < flen && c == static_key_foot[line_index])
		{
		  if (++match == flen)
		    state = PARSE_FINISHED;
		}
	    }

	  /* reading key */
	  if (state == PARSE_DATA)
	    {
	      if (isxdigit(c))
		{
		  ASSERT (hb_index >= 0 && hb_index < 2);
		  hex_byte[hb_index++] = c;
		  if (hb_index == 2)
		    {
		      unsigned int u;
		      ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1);
		      *out++ = u;
		      hb_index = 0;
		      if (++count == keylen)
			state = PARSE_DATA_COMPLETE;
		    }
		}
	      else if (isspace(c))
		;
	      else
		{
		  msg (M_FATAL,
		       (isprint (c) ? printable_char_fmt : unprintable_char_fmt),
		       c, line_num, error_filename, count, onekeylen, keylen);
		}
	    }
	  ++line_index;
	}
      ++cp;
      --size;
    }

  /*
   * Normally we will read either 1 or 2 keys from file.
   */
  key2->n = count / onekeylen;

  ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys));

  if (flags & RKF_MUST_SUCCEED)
    {
      if (!key2->n)
	msg (M_FATAL, "Insufficient key material or header text not found in file '%s' (%d/%d/%d bytes found/min/max)",
	     error_filename, count, onekeylen, keylen);

      if (state != PARSE_FINISHED)
	msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)",
	     error_filename, count, onekeylen, keylen);
    }

  /* zero file read buffer if not an inline file */
  if (!(flags & RKF_INLINE))
    ovpn_buf_clear (&in);

  if (key2->n)
    warn_if_group_others_accessible (error_filename);

#if 0
  /* DEBUGGING */
  {
    int i;
    printf ("KEY READ, n=%d\n", key2->n);
    for (i = 0; i < (int) SIZE (key2->keys); ++i)
      {
	/* format key as ascii */
	const char *fmt = format_hex_ex ((const uint8_t*)&key2->keys[i],
					 sizeof (key2->keys[i]),
					 0,
					 16,
					 "\n",
					 &gc);
	printf ("[%d]\n%s\n\n", i, fmt);
      }
  }
#endif

  /* pop our garbage collection level */
  gc_free (&gc);
}
コード例 #5
0
/*
 * Write key to file, return number of random bits
 * written.
 */
int
write_key_file (const int nkeys, const char *filename)
{
  struct gc_arena gc = gc_new ();

  int fd, i;
  int nbits = 0;

  /* must be large enough to hold full key file */
  struct buffer out = alloc_buf_gc (2048, &gc);
  struct buffer nbits_head_text = alloc_buf_gc (128, &gc);

  /* how to format the ascii file representation of key */
  const int bytes_per_line = 16;

  /* open key file */
  fd = platform_open (filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);

  if (fd == -1)
    msg (M_ERR, "Cannot open shared secret file '%s' for write", filename);

  buf_printf (&out, "%s\n", static_key_head);

  for (i = 0; i < nkeys; ++i)
    {
      struct key key;
      char* fmt;

      /* generate random bits */
      generate_key_random (&key, NULL);

      /* format key as ascii */
      fmt = format_hex_ex ((const uint8_t*)&key,
			   sizeof (key),
			   0,
			   bytes_per_line,
			   "\n",
			   &gc);

      /* increment random bits counter */
      nbits += sizeof (key) * 8;

      /* write to holding buffer */
      buf_printf (&out, "%s\n", fmt);

      /* zero memory which held key component (will be freed by GC) */
      memset (fmt, 0, strlen(fmt));
      CLEAR (key);
    }

  buf_printf (&out, "%s\n", static_key_foot);

  /* write number of bits */
  buf_printf (&nbits_head_text, "#\n# %d bit OpenVPN static key\n#\n", nbits);
  buf_write_string_file (&nbits_head_text, filename, fd);

  /* write key file, now formatted in out, to file */
  buf_write_string_file (&out, filename, fd);

  if (close (fd))
    msg (M_ERR, "Close error on shared secret file %s", filename);

  /* zero memory which held file content (memory will be freed by GC) */
  ovpn_buf_clear (&out);

  /* pop our garbage collection level */
  gc_free (&gc);

  return nbits;
}
コード例 #6
0
ファイル: status.c プロジェクト: benjdag/openvpn
struct status_output *
status_open(const char *filename,
            const int refresh_freq,
            const int msglevel,
            const struct virtual_output *vout,
            const unsigned int flags)
{
    struct status_output *so = NULL;
    if (filename || msglevel >= 0 || vout)
    {
        ALLOC_OBJ_CLEAR(so, struct status_output);
        so->flags = flags;
        so->msglevel = msglevel;
        so->vout = vout;
        so->fd = -1;
        buf_reset(&so->read_buf);
        event_timeout_clear(&so->et);
        if (filename)
        {
            switch (so->flags)
            {
                case STATUS_OUTPUT_WRITE:
                    so->fd = platform_open(filename,
                                           O_CREAT | O_TRUNC | O_WRONLY,
                                           S_IRUSR | S_IWUSR);
                    break;

                case STATUS_OUTPUT_READ:
                    so->fd = platform_open(filename,
                                           O_RDONLY,
                                           S_IRUSR | S_IWUSR);
                    break;

                case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE:
                    so->fd = platform_open(filename,
                                           O_CREAT | O_RDWR,
                                           S_IRUSR | S_IWUSR);
                    break;

                default:
                    ASSERT(0);
            }
            if (so->fd >= 0)
            {
                so->filename = string_alloc(filename, NULL);
                set_cloexec(so->fd);

                /* allocate read buffer */
                if (so->flags & STATUS_OUTPUT_READ)
                {
                    so->read_buf = alloc_buf(512);
                }
            }
            else
            {
                msg(M_WARN, "Note: cannot open %s for %s", filename, print_status_mode(so->flags));
                so->errors = true;
            }
        }
        else
        {
            so->flags = STATUS_OUTPUT_WRITE;
        }

        if ((so->flags & STATUS_OUTPUT_WRITE) && refresh_freq > 0)
        {
            event_timeout_init(&so->et, refresh_freq, 0);
        }
    }
    return so;
}