This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch nm-vpn-username-capture
in repository enlightenment.

View the commit online.

commit 7d9411788f0dfe896180a8ae7dbb9df98fd7701c
Author: [email protected] <[email protected]>
AuthorDate: Sun Jun 21 20:52:47 2026 -0600

    networkmanager: add enm_vpn_username_needed predicate
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../networkmanager/e_networkmanager_vpn_username.c | 46 +++++++++++++++++++
 .../networkmanager/e_networkmanager_vpn_username.h | 51 ++++++++++++++++++++++
 src/modules/networkmanager/meson.build             |  2 +
 src/modules/networkmanager/test_vpn_username.c     | 33 ++++++++++++++
 4 files changed, 132 insertions(+)

diff --git a/src/modules/networkmanager/e_networkmanager_vpn_username.c b/src/modules/networkmanager/e_networkmanager_vpn_username.c
new file mode 100644
index 000000000..c9f8b9b47
--- /dev/null
+++ b/src/modules/networkmanager/e_networkmanager_vpn_username.c
@@ -0,0 +1,46 @@
+#ifdef ENM_VPN_USERNAME_TEST
+/* Standalone unit-test build: no EFL, no config.h. */
+typedef unsigned char Eina_Bool;
+# define EINA_TRUE  1
+# define EINA_FALSE 0
+# include <string.h>
+#else
+# ifdef HAVE_CONFIG_H
+#  include "config.h"
+# endif
+# include <string.h>
+# include <stdlib.h>
+# include "e.h"
+# include "e_networkmanager.h"
+# include "e_networkmanager_import.h"
+# include "e_networkmanager_vpn_username.h"
+#endif
+
+Eina_Bool
+enm_vpn_username_needed(const char *svc_short, const char *conn_type,
+                        const char *current_username)
+{
+   if (current_username && current_username[0]) return EINA_FALSE;
+   if (!svc_short) return EINA_FALSE;
+
+   if (!strcmp(svc_short, "openvpn"))
+     {
+        if (!conn_type) return EINA_FALSE;
+        return (!strcmp(conn_type, "password") ||
+                !strcmp(conn_type, "password-tls"))
+               ? EINA_TRUE : EINA_FALSE;
+     }
+
+   if (!strcmp(svc_short, "pptp")        || !strcmp(svc_short, "l2tp") ||
+       !strcmp(svc_short, "fortisslvpn") || !strcmp(svc_short, "vpnc") ||
+       !strcmp(svc_short, "openswan")    || !strcmp(svc_short, "libreswan") ||
+       !strcmp(svc_short, "strongswan"))
+     return EINA_TRUE;
+
+   return EINA_FALSE;
+}
+
+#ifndef ENM_VPN_USERNAME_TEST
+/* enm_vpn_username_set / enm_vpn_username_dialog / enm_vpn_username_maybe_prompt
+ * are added in Tasks 2 and 3. */
+#endif
diff --git a/src/modules/networkmanager/e_networkmanager_vpn_username.h b/src/modules/networkmanager/e_networkmanager_vpn_username.h
new file mode 100644
index 000000000..24b77b1e1
--- /dev/null
+++ b/src/modules/networkmanager/e_networkmanager_vpn_username.h
@@ -0,0 +1,51 @@
+#ifndef E_NETWORKMANAGER_VPN_USERNAME_H
+#define E_NETWORKMANAGER_VPN_USERNAME_H
+
+#include <Eina.h>
+
+/*
+ * VPN username capture.
+ *
+ * NetworkManager stores a VPN username as a connection *property*
+ * (vpn.data["username"]), not as a secret, and the SecretAgent D-Bus API
+ * (GetSecrets) only ever deals with secrets.  NM therefore never prompts for
+ * a missing username: importing an .ovpn with a bare `auth-user-pass` yields a
+ * connection with password-flags set but no username, which is unusable.
+ *
+ * This long-standing NetworkManager behaviour is reported in:
+ *   - https://bugzilla.redhat.com/show_bug.cgi?id=1535517
+ *   - https://bugzilla.redhat.com/show_bug.cgi?id=1548873
+ *   - https://bbs.archlinux.org/viewtopic.php?id=286378
+ *   - https://bbs.archlinux.org/viewtopic.php?id=225395
+ *   - https://github.com/pop-os/cosmic-settings/issues/1820
+ *
+ * All functions here are MAIN THREAD ONLY.
+ */
+
+/* True when the VPN type uses username auth and current_username is empty.
+ * svc_short is the short service name ("openvpn", "pptp", ...); conn_type is
+ * vpn.data["connection-type"] (may be NULL). */
+Eina_Bool enm_vpn_username_needed(const char *svc_short,
+                                  const char *conn_type,
+                                  const char *current_username);
+
+/* Called with the entered username (NULL on cancel). */
+typedef void (*Enm_Username_Entered_Cb)(void *data, const char *username);
+
+/* Called when the nmcli modify completes. */
+typedef void (*Enm_Username_Done_Cb)(void *data, Eina_Bool ok);
+
+/* Persist username to vpn.data["username"] via `nmcli connection modify`. */
+void enm_vpn_username_set(const char *conn_name, const char *username,
+                          Enm_Username_Done_Cb cb, void *data);
+
+/* Single-field username dialog.  Calls cb(username) on OK, cb(NULL) on cancel. */
+void enm_vpn_username_dialog(const char *conn_name, const char *type_label,
+                             const char *initial,
+                             Enm_Username_Entered_Cb cb, void *data);
+
+/* Post-import orchestrator: query the connection, and if it needs a username,
+ * prompt for one and persist it.  Fire-and-forget. */
+void enm_vpn_username_maybe_prompt(const char *conn_name);
+
+#endif
diff --git a/src/modules/networkmanager/meson.build b/src/modules/networkmanager/meson.build
index b83a30442..6fb04a071 100644
--- a/src/modules/networkmanager/meson.build
+++ b/src/modules/networkmanager/meson.build
@@ -8,6 +8,8 @@ src = ""
   'e_networkmanager_vpn.h',
   'e_networkmanager_import.c',
   'e_networkmanager_import.h',
+  'e_networkmanager_vpn_username.c',
+  'e_networkmanager_vpn_username.h',
   'e_mod_main.h'
 )
 
diff --git a/src/modules/networkmanager/test_vpn_username.c b/src/modules/networkmanager/test_vpn_username.c
new file mode 100644
index 000000000..740dd4377
--- /dev/null
+++ b/src/modules/networkmanager/test_vpn_username.c
@@ -0,0 +1,33 @@
+/* Standalone unit test for enm_vpn_username_needed.
+ * Build: gcc -DENM_VPN_USERNAME_TEST test_vpn_username.c -o /tmp/t && /tmp/t */
+#include <assert.h>
+#include <stdio.h>
+
+#define ENM_VPN_USERNAME_TEST 1
+#include "e_networkmanager_vpn_username.c"
+
+int main(void)
+{
+   /* openvpn: only password / password-tls need a username */
+   assert(enm_vpn_username_needed("openvpn", "password", NULL));
+   assert(enm_vpn_username_needed("openvpn", "password-tls", ""));
+   assert(!enm_vpn_username_needed("openvpn", "tls", NULL));
+   assert(!enm_vpn_username_needed("openvpn", NULL, NULL));
+
+   /* already has a username -> never needed */
+   assert(!enm_vpn_username_needed("openvpn", "password", "alice"));
+
+   /* xauth / password-based types always need it when empty */
+   assert(enm_vpn_username_needed("pptp", NULL, NULL));
+   assert(enm_vpn_username_needed("l2tp", NULL, ""));
+   assert(enm_vpn_username_needed("vpnc", NULL, NULL));
+   assert(enm_vpn_username_needed("libreswan", NULL, NULL));
+   assert(!enm_vpn_username_needed("libreswan", NULL, "bob"));
+
+   /* unknown / NULL type -> not needed */
+   assert(!enm_vpn_username_needed("wireguard", NULL, NULL));
+   assert(!enm_vpn_username_needed(NULL, NULL, NULL));
+
+   printf("all enm_vpn_username_needed assertions passed\n");
+   return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to