Skip to contentSkip to conversation

WTMP support for OpenVPN 2.1

Openvpn-devel New Maximilian Wilhelm 1 participant 10 messages Sep 2, 2007 – Sep 10, 2007 Kbuild

lore
Share & tools
lore
#0 lore raw

Hi!

This is an initial attempt to let OpenVPN 2.1 write a wtmp log of all connections including the username, it's VPN IP and the real remote IP the user connected from.

This provides an OpenVPN admin with a simple database of all connections of his VPN servers and the possibility to easily see if anyone is using the VPN server currently.

It is possible to let multiple instances of OpenVPN on the same host use the same wtmp file by specifying different "server ids" which are a two digit integer which will be used in the wtmp line string to distinguish between vpn sessions.

This implementation does work, but has some things which have to be done better:

* There has to be used a unique session id per VPN session which does not change between reconnecteds (currently the ssl session_id is used as identifier)

* At the moment the uid/gid for the username/groupname config options are looked up by hand in wtmp_init() as the context->c0 struct is not yet available.
Maybe wtmp_init() could be called a bit later at a usefull place to avoid this doulbe lookup.

These are the "known bugs" my implementation has, but which are still on my todo list (the second one is kind of WORKS_FOR_ME) :)

So if anyone has comments or ideas how to do things better, don't hasitate and let me know.

I would very much like to get thos included in OpenVPN as it will help people to have an overview about the usage of the VPNs and was requested earlier.

Ciao
Max

#1 lore raw

PATCH 1/1 Let multi.c call wtmp_* routines when ENABLE_WTMP is defined.

---
 multi.c |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)
multi.c +16 -0
index fa924f1..2c23a44 100644
@@ -42,6 +42,10 @@
 
 #include "forward-inline.h"
 
+#ifdef ENABLE_WTMP
+#include "wtmp.h"
+#endif
+
 /*#define MULTI_DEBUG_EVENT_LOOP*/
 
 #ifdef MULTI_DEBUG_EVENT_LOOP
@@ -457,6 +461,10 @@ multi_close_instance (struct multi_context *m,
 
   dmsg (D_MULTI_DEBUG, "MULTI: multi_close_instance called");
 
+#ifdef ENABLE_WTMP
+  wtmp_stop (mi);
+#endif
+
   /* prevent dangling pointers */
   if (m->pending == mi)
     multi_set_pending (m, NULL);
@@ -1444,6 +1452,10 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 	}
 #endif
 
+#ifdef ENABLE_WTMP
+      wtmp_start (mi);
+#endif
+
       /*
        * Run --client-connect script.
        */
@@ -2289,6 +2301,10 @@ tunnel_server (struct context *top)
 {
   ASSERT (top->options.mode == MODE_SERVER);
 
+#ifdef ENABLE_WTMP
+  wtmp_init();
+#endif
+
   switch (top->options.proto) {
   case PROTO_UDPv4:
     tunnel_server_udp (top);
Signature · 1 line
1.5.2.4
#2 lore raw

PATCH 1/1 Added the ability to configure wtmp logging:

In reply to Maximilian Wilhelm

--log-wtmp server_id [file] : Enable logging to wtmp file using the two digit
server_id a prefix for the utmp line. Optionally you can write to an own wtmp file. (Default is /var/log/ovpnwtmp.

---
 options.c |   31 +++++++++++++++++++++++++++++++
 options.h |    6 ++++++
 2 files changed, 37 insertions(+), 0 deletions(-)
options.c +31 -0
index 46aad6d..a8c0073 100644
@@ -266,6 +266,11 @@ static const char usage_message[] =
   "--suppress-timestamps : Don't log timestamps to stdout/stderr.\n"
   "--writepid file : Write main process ID to file.\n"
   "--nice n        : Change process priority (>0 = lower, <0 = higher).\n"
+#ifdef ENABLE_WTMP
+  "--log-wtmp server_id [file] : Enable logging to wtmp file using the two digit\n"
+  "                  server_id a prefix for the utmp line. Optionally you can write\n"
+  "                  to an own wtmp file. (Default is /var/log/ovpnwtmp.\n"
+#endif
 #if 0
 #ifdef USE_PTHREAD
   "--nice-work n   : Change thread priority of work thread.  The work\n"
@@ -697,6 +702,12 @@ init_options (struct options *o)
 #ifdef ENABLE_PKCS11
   o->pkcs11_pin_cache_period = -1;
 #endif			/* ENABLE_PKCS11 */
+
+#ifdef ENABLE_WTMP
+  o->log_wtmp = 0;
+  o->wtmp_server_id = 1;
+  o->wtmp_file = "/var/log/ovpnwtmp";
+#endif
 }
 
 void
@@ -3473,6 +3484,25 @@ add_option (struct options *options,
       options->log = true;
       redirect_stdout_stderr (p[1], false);
     }
+
+#ifdef ENABLE_WTMP
+  else if (streq (p[0], "log-wtmp") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+
+      /* Activate WTMP logging */
+      options->log_wtmp = 1;
+
+      /* Use server_id if set */
+      if (p[1])
+        options->wtmp_server_id = atoi (p[1]);
+
+      /* User specified wtmp file if set */
+      if (p[2])
+        options->wtmp_file = p[2];
+      }
+#endif
+
   else if (streq (p[0], "suppress-timestamps"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -3773,6 +3803,7 @@ add_option (struct options *options,
       openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
     }
 #endif /* GENERAL_PROXY_SUPPORT */
+
 #ifdef ENABLE_HTTP_PROXY
   else if (streq (p[0], "http-proxy") && p[1])
     {
options.h +6 -0
index 21d131e..e7a49b9 100644
@@ -214,6 +214,12 @@ struct options
   /* inetd modes defined in socket.h */
   int inetd;
 
+#ifdef ENABLE_WTMP
+  int log_wtmp;
+  int wtmp_server_id;
+  char *wtmp_file;
+#endif
+
   bool log;
   bool suppress_timestamps;
   int nice;
Signature · 1 line
1.5.2.4
#3 lore raw

PATCH 1/1 Let OpenVPN write wtmp entries if configured so.

In reply to Maximilian Wilhelm
---
 multi.c |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)
multi.c +7 -3
index 2c23a44..5d8c80e 100644
@@ -462,7 +462,9 @@ multi_close_instance (struct multi_context *m,
   dmsg (D_MULTI_DEBUG, "MULTI: multi_close_instance called");
 
 #ifdef ENABLE_WTMP
-  wtmp_stop (mi);
+  if (m->top.options.log_wtmp == 1)
+    wtmp_stop (mi);
+
 #endif
 
   /* prevent dangling pointers */
@@ -1453,7 +1455,8 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 #endif
 
 #ifdef ENABLE_WTMP
-      wtmp_start (mi);
+      if (m->top.options.log_wtmp == 1)
+        wtmp_start (mi);
 #endif
 
       /*
@@ -2302,7 +2305,8 @@ tunnel_server (struct context *top)
   ASSERT (top->options.mode == MODE_SERVER);
 
 #ifdef ENABLE_WTMP
-  wtmp_init();
+  if (top->options.log_wtmp == 1)
+    wtmp_init(top->options.wtmp_server_id, top->options.wtmp_file);
 #endif
 
   switch (top->options.proto) {
Signature · 1 line
1.5.2.4
#4 lore raw

PATCH 1/1 Added WTMP support for OpenVPN

In reply to Maximilian Wilhelm
---
 wtmp.c |  333 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 wtmp.h |   27 +++++
 2 files changed, 360 insertions(+), 0 deletions(-)
 create mode 100644 wtmp.c
 create mode 100644 wtmp.h
wtmp.c new file +333 -0
new file mode 100644
index 0000000..39822df
@@ -0,0 +1,333 @@
+/*
+ * OpenVPN wtmp support
+ *
+ * Copyright: 2007 Maximilian Wilhelm <[email protected]...>
+ *
+ */
+
+#include "config.h"
+#include "syshead.h"
+
+#ifdef ENABLE_WTMP
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <dirent.h>	/* opendir() */
+#include <stdio.h>	/* fopen() */
+#include <stdlib.h>	/* *alloc(), free() */
+#include <string.h>	/* strncpy(), strlen() */
+#include <sys/stat.h>	/* stat() */
+#include <sys/time.h>	/* struct timeval */
+#include <sys/types.h>	/* opendir() */
+#include <utmp.h>	/* utmp foo */
+
+#include "openvpn.h"	/* struct context* */
+#include "forward.h"
+#include "forward-inline.h"
+#include "multi.h"	/* struct multi_instance */
+#include "buffer.h"	/* struct buffer */
+
+#include "wtmp.h"
+
+int wtmp_active = 0;
+
+#define HAVE_ENDUTENT 1
+
+#define OVPN_WTMP_DEBUG 1
+
+/*
+ * Initialize wtmp subsystem
+ */
+int
+wtmp_init (unsigned int server_id, const char *wtmp_file_path)
+{
+#ifdef OVPN_WTMP_DEBUG
+	fprintf (stderr, "%s() called.\n", __FUNCTION__);
+#endif
+
+	struct stat wtmp_stat;
+	char *wtmp_file_dirname;
+	char *wtmp_file_path_copy;
+
+	/* Only initialize once */
+	if (wtmp_active == 1)
+		return 1;
+
+#ifdef OVPN_WTMP_DEBUG
+	fprintf (stderr, "wtmp_file_path = %s\n", wtmp_file_path);
+#endif
+
+	wtmp_file_path_copy = strdup (wtmp_file_path);
+	wtmp_file_dirname = dirname (wtmp_file_path_copy);
+
+	/* Check if WTMP_DIR exists and try to create it if not */
+	if (! opendir (wtmp_file_dirname)) {
+		fprintf (stderr, "%s: wtmp_file_dirname %s does not exist. Trying to create it.\n",
+			__FUNCTION__, wtmp_file_dirname);
+
+		if (mkdir (wtmp_file_dirname, 0700)) {
+			fprintf (stderr, "%s: Could not create directory %s\n",
+				__FUNCTION__, wtmp_file_dirname);
+			wtmp_active = 0;
+			goto out;
+		}
+
+		fprintf (stderr, "%s: Successfully created wtmp_file_dirname %s.\n",
+			__FUNCTION__, wtmp_file_dirname);
+	}
+
+	/* Check if wtmp_file_path exists and try to create it if not */
+	if (stat (wtmp_file_path, &wtmp_stat)) {
+		fprintf (stderr, "%s: wtmp_file %s does not exist or is not accessable. Trying to create it.\n",
+			__FUNCTION__, wtmp_file_path);
+
+		/* Touch wtmp_file */
+		if (! fopen (wtmp_file_path, "a")) {
+			fprintf (stderr, "%s: Could not create file %s.\n",
+				__FUNCTION__, wtmp_file_path);
+				wtmp_active = 0;
+				goto out;
+		}
+
+		fprintf (stderr, "%s: Successfully created wtmp_file %s.\n",
+			__FUNCTION__, wtmp_file_path);
+	} /* [ ! -f wtmp_file ] */
+
+	/* OK wtmp_file is (now) there, use it */
+	utmpname (wtmp_file_path);
+
+	/* Everything is fine */
+	wtmp_active = 1;
+
+out:
+	free (wtmp_file_path_copy);
+
+	return wtmp_active;
+}
+
+
+void
+wtmp_start (const struct multi_instance *mi)
+{
+#ifdef OVPN_WTMP_DEBUG
+	fprintf (stderr, "%s() called.\n", __FUNCTION__);
+#endif
+
+	struct utmp entry;
+        struct sockaddr_in *remote_addr;
+
+	char *temp;
+
+	if (wtmp_active == 0)
+		return;
+
+	/* Get IP address of this connection
+	 * FIXME: IPv6?!
+	 */
+	remote_addr = get_remote_sockaddr_from_multi_instance (mi);
+	if (! remote_addr) {
+		fprintf (stderr, "%s: get_remote_sockaddr_from_multi_instance (mi) failed.\n",
+			__FUNCTION__);
+	}
+
+	/* Clear entry */
+	memset(&entry, '\0', sizeof (entry));
+
+	/* This entry is a user process */
+	entry.ut_type = USER_PROCESS;
+
+	/* The connection started now, so set epoch time */
+	set_utmp_time (&entry);
+
+	/* Set the user name */
+	set_utmp_username (mi, &entry);
+
+	/* Set the line */
+	set_utmp_line (mi, &entry);
+
+	/* Store the IP we gave this client as the hostname */
+	set_utmp_hostname (mi, &entry);
+
+	/* Use the first 4 chars of the session ID as id */
+	set_utmp_id (mi, &entry);
+
+	/* Store the remote client IP(v4), if available */
+	entry.ut_addr = remote_addr->sin_addr.s_addr;
+
+#ifdef OVPN_WTMP_DEBUG
+fprintf (stderr, "%s: entry.ut_line = \"%s\"\n", __FUNCTION__, entry.ut_line);
+fprintf (stderr, "%s: entry.ut_id = \"%s\"\n",   __FUNCTION__, entry.ut_id);
+fprintf (stderr, "%s: entry.ut_user = \"%s\"\n", __FUNCTION__, entry.ut_user);
+fprintf (stderr, "%s: entry.ut_host = \"%s\"\n", __FUNCTION__, entry.ut_host);
+
+unsigned int ip = ntohl (entry.ut_addr);
+fprintf (stderr, "%s: entry.ut_addr = %d.%d.%d.%d\n", __FUNCTION__,  ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, (ip >> 0) & 0xff);
+#endif
+
+	updwtmp (mi->context.options.wtmp_file, &entry);
+}
+
+
+void
+wtmp_stop (const struct multi_instance *mi)
+{
+#ifdef OVPN_WTMP_DEBUG
+	fprintf (stderr, "%s() called.\n", __FUNCTION__);
+#endif
+
+	struct utmp entry;
+
+	if (wtmp_active == 0)
+		return;
+
+	/* Clear entry */
+	memset (&entry, '\0', sizeof (entry));
+
+	/* The connection stopped now, so set epoch time */
+	set_utmp_time (&entry);
+
+	/* He's dead jim */
+	entry.ut_type = DEAD_PROCESS;
+
+	/* Set current epoch time */
+	set_utmp_time (&entry);
+
+	/* Set the line */
+	set_utmp_line (mi, &entry);
+
+	/* Use the first 4 chars of the session ID as id */
+	set_utmp_id (mi, &entry);
+
+	entry.ut_host[0] = 0;
+
+#ifdef OVPN_WTMP_DEBUG
+fprintf (stderr, "%s: entry.ut_line = %s\n", __FUNCTION__, entry.ut_line);
+fprintf (stderr, "%s: entry.ut_id = %s\n", __FUNCTION__, entry.ut_id);
+#endif
+
+	updwtmp (mi->context.options.wtmp_file, &entry);
+}
+
+
+
+
+
+/* Build up and store an utmp line */
+void
+set_utmp_line (const struct multi_instance *mi, struct utmp *entry)
+{
+	struct gc_arena gc = gc_new ();
+	char *temp;
+
+	char line[UT_LINESIZE];
+
+	/* Should be config option */
+	unsigned int server_num = 1;
+
+	assert (mi);
+	assert (entry);
+
+	temp = format_hex_ex (mi->context.c2.tls_multi->session[TM_ACTIVE].session_id.id, SID_SIZE, 0, 4, "", &gc);
+
+	if (temp) {
+		snprintf (entry->ut_line, UT_LINESIZE, "ovpn%02d-%s", server_num, temp);
+	} else {
+		snprintf (entry->ut_line, UT_LINESIZE, "ovpn%02d", server_num);
+	}
+}
+
+
+/* Store the first 4 chars of the session_id as the utmp id */
+void
+set_utmp_id (const struct multi_instance *mi, struct utmp *entry)
+{
+	struct gc_arena gc = gc_new ();
+	char *temp;
+
+	assert (mi);
+	assert (entry);
+
+	temp = format_hex_ex (mi->context.c2.tls_multi->session[TM_ACTIVE].session_id.id, SID_SIZE, 0, 4, " ", &gc);
+	if (temp) {
+		snprintf (entry->ut_id, 4, "%s", temp);
+	}
+}
+
+
+/* Store a human readable format of the VPN ip address we gave to the client as utmp hostname */
+void
+set_utmp_hostname (const struct multi_instance *mi, struct utmp *entry)
+{
+	unsigned int ip;
+
+	assert (mi);
+	assert (entry);
+
+	memset (entry->ut_host, '\0', UT_HOSTSIZE);
+
+	ip =  mi->context.c2.push_ifconfig_local;
+	snprintf (entry->ut_host, UT_HOSTSIZE, "%d.%d.%d.%d", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, (ip >> 0) & 0xff);
+}
+
+
+/* Store the username of the current session in the utmp entry */
+void
+set_utmp_username (const struct multi_instance *mi, struct utmp *entry)
+{
+	const char *username;
+
+	assert (mi);
+	assert (entry);
+
+	username = tls_common_name (mi->context.c2.tls_multi, false);
+	if (username) {
+		snprintf (entry->ut_user, UT_NAMESIZE, "%s", username);
+	} else {
+		snprintf (entry->ut_user, UT_NAMESIZE, "unknown");
+	}
+}
+
+
+/* Get a sockaddr_in struct containing the real IP of the remote host */
+static struct sockaddr_in *
+get_remote_sockaddr_from_multi_instance (const struct multi_instance *mi)
+{
+	struct buffer buf ;
+	struct link_socket_actual *lsa;
+
+	assert (mi);
+
+	lsa = calloc (1, sizeof (struct link_socket_actual));
+	if (! lsa)
+		return NULL;
+
+	link_socket_get_outgoing_addr (&buf, get_link_socket_info (&mi->context), &lsa);
+
+	return &lsa->dest.sa;
+}
+
+
+/*
+ * Some helper functions, partly stolen from OpenSSH/loginrec.c
+ *
+ */
+
+
+/* Store the current time in utmp struct */
+static void
+set_utmp_time (struct utmp *ut)
+{
+	struct timeval tv;
+
+	assert (ut);
+
+	gettimeofday(&tv, NULL);
+	ut->ut_tv.tv_sec = tv.tv_sec;
+	ut->ut_tv.tv_usec = tv.tv_usec;
+
+	ut->ut_time = tv.tv_sec;
+}
+#endif /* ENABLE_WTMP */
+
+
wtmp.h new file +27 -0
new file mode 100644
index 0000000..c43b472
@@ -0,0 +1,27 @@
+#ifndef _OPENVPN_WTMP_H
+#define _OPENVPN_WTMP_H
+
+#include <utmp.h>
+
+#include "multi.h"
+
+#define OVPN_WTMP_DIR  "/tmp"
+#define OVPN_WTMP_FILENAME "ovpnwtmp"
+
+enum local_remote { LOCAL, REMOTE };
+
+int wtmp_init ();
+
+void wtmp_start (const struct multi_instance *mi);
+void wtmp_stop (const struct multi_instance *mi);
+
+static void set_utmp_time (struct utmp *ut);
+
+void set_utmp_hostname (const struct multi_instance *mi, struct utmp *entry);
+void set_utmp_id (const struct multi_instance *mi, struct utmp *entry);
+void set_utmp_line (const struct multi_instance *mi, struct utmp *entry);
+void set_utmp_username (const struct multi_instance *mi, struct utmp *entry);
+
+static struct sockaddr_in * get_remote_sockaddr_from_multi_instance (const struct multi_instance *mi);
+
+#endif /* _OPENVPN_WTMP_H */
Signature · 1 line
1.5.2.4
#6 lore raw

PATCH 1/1 Push a pointer to the whole options struct to wtmp_init()

In reply to Maximilian Wilhelm

This change introduces the ability to figure out as which user OpenVPN will run after dropping privileges. This is very usefull when creating the wtmp file, which by default is owned by root resulting in OpenVPN not being able to write to it.

So now the owner and group can be changed to the names specified in the configuration.

---
 multi.c   |    2 +-
 options.c |    3 ++-
 wtmp.c    |   13 +++++++++----
 wtmp.h    |    2 +-
 4 files changed, 13 insertions(+), 7 deletions(-)
multi.c +1 -1
index 5d8c80e..1453399 100644
@@ -2306,7 +2306,7 @@ tunnel_server (struct context *top)
 
 #ifdef ENABLE_WTMP
   if (top->options.log_wtmp == 1)
-    wtmp_init(top->options.wtmp_server_id, top->options.wtmp_file);
+    wtmp_init (&top->options);
 #endif
 
   switch (top->options.proto) {
options.c +2 -1
index a8c0073..ed269c6 100644
@@ -3500,7 +3500,8 @@ add_option (struct options *options,
       /* User specified wtmp file if set */
       if (p[2])
         options->wtmp_file = p[2];
-      }
+
+    }
 #endif
 
   else if (streq (p[0], "suppress-timestamps"))
wtmp.c +9 -4
index 39822df..3887220 100644
@@ -32,28 +32,33 @@
 
 int wtmp_active = 0;
 
-#define HAVE_ENDUTENT 1
-
-#define OVPN_WTMP_DEBUG 1
+// #define OVPN_WTMP_DEBUG 1
 
 /*
  * Initialize wtmp subsystem
  */
 int
-wtmp_init (unsigned int server_id, const char *wtmp_file_path)
+wtmp_init (const struct options *vpn_options)
 {
 #ifdef OVPN_WTMP_DEBUG
 	fprintf (stderr, "%s() called.\n", __FUNCTION__);
 #endif
 
 	struct stat wtmp_stat;
+
+	char *wtmp_file_path;
+
 	char *wtmp_file_dirname;
 	char *wtmp_file_path_copy;
 
+	assert (options);
+
 	/* Only initialize once */
 	if (wtmp_active == 1)
 		return 1;
 
+	wtmp_file_path = vpn_options->wtmp_file;
+
 #ifdef OVPN_WTMP_DEBUG
 	fprintf (stderr, "wtmp_file_path = %s\n", wtmp_file_path);
 #endif
wtmp.h +1 -1
index c43b472..7fd3927 100644
@@ -10,7 +10,7 @@
 
 enum local_remote { LOCAL, REMOTE };
 
-int wtmp_init ();
+int wtmp_init (const struct options *vpn_options);
 
 void wtmp_start (const struct multi_instance *mi);
 void wtmp_stop (const struct multi_instance *mi);
Signature · 1 line
1.5.2.4
#7 lore raw

PATCH 1/1 Let set_utmp_line() use the configured 'server_id' as prefix in utmp line string

In reply to Maximilian Wilhelm

Now every utmp line will look like "ovpn%d-%s" where %d are the two last digits of the server_id and %s some chars of the session_id (as many as fit into the remaining space in 'ut_line'.

This provides the ability to let at most 100 OpenVPN instances on one single maschine write to the same wtmp file and you are still able to distinguish which instance created which entry.

---
 wtmp.c |   14 +++++---------
 1 files changed, 5 insertions(+), 9 deletions(-)
wtmp.c +5 -9
index 3887220..50dd5f9 100644
@@ -216,29 +216,25 @@ fprintf (stderr, "%s: entry.ut_id = %s\n", __FUNCTION__, entry.ut_id);
 
 
 
-
-
 /* Build up and store an utmp line */
 void
 set_utmp_line (const struct multi_instance *mi, struct utmp *entry)
 {
 	struct gc_arena gc = gc_new ();
-	char *temp;
 
-	char line[UT_LINESIZE];
-
-	/* Should be config option */
-	unsigned int server_num = 1;
+	char *temp;
+	unsigned int server_id
 
 	assert (mi);
 	assert (entry);
 
+	server_id = mi->context.options.wtmp_server_id % 100;
 	temp = format_hex_ex (mi->context.c2.tls_multi->session[TM_ACTIVE].session_id.id, SID_SIZE, 0, 4, "", &gc);
 
 	if (temp) {
-		snprintf (entry->ut_line, UT_LINESIZE, "ovpn%02d-%s", server_num, temp);
+		snprintf (entry->ut_line, UT_LINESIZE, "ovpn%02d-%s", server_id, temp);
 	} else {
-		snprintf (entry->ut_line, UT_LINESIZE, "ovpn%02d", server_num);
+		snprintf (entry->ut_line, UT_LINESIZE, "ovpn%02d", server_id);
 	}
 }
 
Signature · 1 line
1.5.2.4
#8 lore raw

PATCH 1/1 wtmp_init() does not honor username/groupname config options and chown()s wtmp file

In reply to Maximilian Wilhelm

Now wtmp_init() does try to lookup the uid for "username" and the gid for "groupname" if configured and - if successfull - chown the wtmp file to this combination.

(The lookup of uid/gid is neccessary here as 'context->c0' is no yet
initialized at the point wtmp_init() is called.)

---
 wtmp.c |   47 +++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 43 insertions(+), 4 deletions(-)
wtmp.c +43 -4
index 50dd5f9..374cf53 100644
@@ -12,14 +12,16 @@
 
 #define _GNU_SOURCE
 
-#include <assert.h>
+#include <assert.h>	/* assert() */
 #include <dirent.h>	/* opendir() */
+#include <pwd.h>	/* struct passwd */
 #include <stdio.h>	/* fopen() */
 #include <stdlib.h>	/* *alloc(), free() */
 #include <string.h>	/* strncpy(), strlen() */
 #include <sys/stat.h>	/* stat() */
 #include <sys/time.h>	/* struct timeval */
-#include <sys/types.h>	/* opendir() */
+#include <sys/types.h>	/* opendir() chown()  */
+#include <unistd.h>	/* chown() */
 #include <utmp.h>	/* utmp foo */
 
 #include "openvpn.h"	/* struct context* */
@@ -46,12 +48,20 @@ wtmp_init (const struct options *vpn_options)
 
 	struct stat wtmp_stat;
 
+	/* These will be used when getting the uid/gid to chown the wtmp file */
+	struct passwd *pw;
+	struct group *grp;
+	unsigned short do_chmod = 2;
+	uid_t uid = -1;
+	gid_t gid = -1;
+
+	/* The wtmp file we're going to write to */
 	char *wtmp_file_path;
 
 	char *wtmp_file_dirname;
 	char *wtmp_file_path_copy;
 
-	assert (options);
+	assert (vpn_options);
 
 	/* Only initialize once */
 	if (wtmp_active == 1)
@@ -66,6 +76,24 @@ wtmp_init (const struct options *vpn_options)
 	wtmp_file_path_copy = strdup (wtmp_file_path);
 	wtmp_file_dirname = dirname (wtmp_file_path_copy);
 
+	/* Get UID and GID of the configured user and group */
+	if (vpn_options->username) {
+		pw = getpwnam (vpn_options->username);
+		if (pw)
+			uid = pw->pw_uid;
+		else
+			do_chmod -= 1;
+	}
+
+	if (vpn_options->groupname) {
+		grp = getgrnam (vpn_options->groupname);
+		if (grp)
+			gid = grp->gr_gid;
+		else
+			do_chmod -= 1;
+
+	}
+
 	/* Check if WTMP_DIR exists and try to create it if not */
 	if (! opendir (wtmp_file_dirname)) {
 		fprintf (stderr, "%s: wtmp_file_dirname %s does not exist. Trying to create it.\n",
@@ -99,6 +127,17 @@ wtmp_init (const struct options *vpn_options)
 			__FUNCTION__, wtmp_file_path);
 	} /* [ ! -f wtmp_file ] */
 
+	/* Maybe one changed "username" and "group" config options */
+	if (do_chmod == 2) {
+		if (chown (wtmp_file_path, uid, gid)) {
+			fprintf (stderr, "%s: Could not set owner/group of wtmp file %s.\n",
+				__FUNCTION__, wtmp_file_path);
+				wtmp_active = 0;
+				goto out;
+		}
+	}
+
+
 	/* OK wtmp_file is (now) there, use it */
 	utmpname (wtmp_file_path);
 
@@ -223,7 +262,7 @@ set_utmp_line (const struct multi_instance *mi, struct utmp *entry)
 	struct gc_arena gc = gc_new ();
 
 	char *temp;
-	unsigned int server_id
+	unsigned int server_id;
 
 	assert (mi);
 	assert (entry);
Signature · 1 line
1.5.2.4
#9 lore raw
In reply to Maximilian Wilhelm

Am Monday, den 3 September hub Maximilian Wilhelm folgendes in die Tasten:

Hi!

Quoted 3 lines

This is an initial attempt to let OpenVPN 2.1 write a wtmp log of all connections including the username, it's VPN IP and the real remote IP the user connected from.

[...]

Is nobody interested in this?

That would be very sad.

Ciao
Max

Signature · 1 line
	Follow the white penguin.