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

git pushed a commit to branch master
in repository enlightenment.

View the commit online.

commit de6e0564b217943a259b2e3a461691eaa63151a6
Author: Carsten Haitzler <[email protected]>
AuthorDate: Wed Jun 17 12:10:05 2026 +0100

    nm - please actually display and read and provide secrets and messages
---
 src/modules/networkmanager/agent.c            | 232 +++++++++++++----
 src/modules/networkmanager/e_networkmanager.c | 343 ++++++++++++++++++++++----
 src/modules/networkmanager/e_networkmanager.h |   1 +
 3 files changed, 490 insertions(+), 86 deletions(-)

diff --git a/src/modules/networkmanager/agent.c b/src/modules/networkmanager/agent.c
index 4de8ad071..c1c85e058 100644
--- a/src/modules/networkmanager/agent.c
+++ b/src/modules/networkmanager/agent.c
@@ -3,6 +3,7 @@
 #endif
 
 #include <stdbool.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -40,6 +41,10 @@ struct _E_NM_Agent_Dialog
 
 static E_NM_Agent_Dialog *_current_dialog = NULL;
 
+#define NM_SECRET_TAG_VPN_MSG                 "x-vpn-message:"
+#define NM_SECRET_TAG_DYNAMIC_CHALLENGE       "x-dynamic-challenge:"
+#define NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO  "x-dynamic-challenge-echo:"
+
 /* -------------------------------------------------------------------------- */
 /* Dialog callbacks                                                            */
 /* -------------------------------------------------------------------------- */
@@ -163,6 +168,108 @@ _show_password_cb(void *data, Evas_Object *obj, void *event EINA_UNUSED)
    elm_entry_password_set(entry, !elm_check_state_get(obj));
 }
 
+static Eina_Bool
+_vpn_field_is_password(const char *field)
+{
+   char lower[128];
+   size_t i;
+
+   if (!field) return EINA_TRUE;
+   if (!strncmp(field, NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO,
+                strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO)))
+     return EINA_FALSE;
+
+   for (i = 0; field[i] && i < sizeof(lower) - 1; i++)
+     lower[i] = (char)tolower((unsigned char)field[i]);
+   lower[i] = '\0';
+
+   if (strstr(lower, "password") || strstr(lower, "pass") ||
+       strstr(lower, "secret") || strstr(lower, "psk") ||
+       strstr(lower, "cookie"))
+     return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static const char *
+_vpn_field_label_get(const char *field)
+{
+   if (!field) return _("Secret");
+   if (!strncmp(field, NM_SECRET_TAG_DYNAMIC_CHALLENGE,
+                strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE)))
+     return field + strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE);
+   if (!strncmp(field, NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO,
+                strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO)))
+     return field + strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO);
+   if (!strcmp(field, "username")) return _("Username");
+   if (!strcmp(field, "user-name")) return _("Username");
+   if (!strcmp(field, "password")) return _("Password");
+   if (!strcmp(field, "cert-pass")) return _("Certificate password");
+   if (!strcmp(field, "http-proxy-password")) return _("HTTP proxy password");
+   if (!strcmp(field, "Xauth password")) return _("Password");
+   if (!strcmp(field, "IPSec secret")) return _("Group password");
+   if (!strcmp(field, "xauthpassword")) return _("Password");
+   if (!strcmp(field, "pskvalue")) return _("Group password");
+   if (!strcmp(field, "gateway")) return _("Gateway URL");
+   if (!strcmp(field, "cookie")) return _("Cookie");
+   if (!strcmp(field, "gwcert")) return _("Gateway certificate hash");
+   if (!strcmp(field, "resolve")) return _("Gateway DNS resolution ('host:IP')");
+   if (!strncmp(field, NM_SECRET_TAG_VPN_MSG, strlen(NM_SECRET_TAG_VPN_MSG)))
+     return field + strlen(NM_SECRET_TAG_VPN_MSG);
+   return field;
+}
+
+static int
+_vpn_field_order_get(const char *field)
+{
+   if (!field) return 100;
+   if (!strcmp(field, "username") || !strcmp(field, "user-name"))
+     return 0;
+   if (!strcmp(field, "password"))
+     return 1;
+   if (strstr(field, "username") || strstr(field, "user-name"))
+     return 2;
+   if (_vpn_field_is_password(field))
+     return 3;
+   return 50;
+}
+
+static int
+_vpn_field_order_find(const char *const *fields, unsigned int n_fields,
+                      Eina_Bool *used)
+{
+   unsigned int best = n_fields;
+   int best_order = 0;
+
+   for (unsigned int i = 0; i < n_fields; i++)
+     {
+        int order;
+
+        if (used[i]) continue;
+        order = _vpn_field_order_get(fields[i]);
+        if ((best == n_fields) || (order < best_order))
+          {
+             best = i;
+             best_order = order;
+          }
+     }
+
+   return best == n_fields ? -1 : (int)best;
+}
+
+static void
+_field_column_min_width_set(Evas_Object *table, int col)
+{
+   Evas_Object *rect;
+
+   rect = evas_object_rectangle_add(evas_object_evas_get(table));
+   evas_object_color_set(rect, 0, 0, 0, 0);
+   evas_object_size_hint_min_set(rect, 300 * e_scale, 1);
+   evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, 0);
+   evas_object_size_hint_align_set(rect, EVAS_HINT_FILL, 0.0);
+   elm_table_pack(table, rect, col, 0, 1, 1);
+   evas_object_show(rect);
+}
+
 /* -------------------------------------------------------------------------- */
 /* Dialog construction                                                         */
 /* -------------------------------------------------------------------------- */
@@ -171,7 +278,7 @@ static E_NM_Agent_Dialog *
 _dialog_new(E_NM_Agent_Request *req, const char *ssid)
 {
    E_NM_Agent_Dialog *ad;
-   Evas_Object *frame, *box, *entry, *check;
+   Evas_Object *frame, *table, *label, *entry, *check;
    E_Dialog    *dialog;
    char         header[128];
 
@@ -183,30 +290,36 @@ _dialog_new(E_NM_Agent_Request *req, const char *ssid)
    ad->req     = req;
    ad->is_vpn  = EINA_FALSE;
 
-   e_dialog_resizable_set(dialog, 1);
+   e_dialog_resizable_set(dialog, 0);
    e_dialog_title_set(dialog, _("WiFi Password Required"));
    e_dialog_border_icon_set(dialog, "dialog-password");
 
    e_dialog_button_add(dialog, _("Connect"), NULL, _dialog_ok_cb, ad);
    e_dialog_button_add(dialog, _("Cancel"),  NULL, _dialog_cancel_cb, ad);
 
-   /* Labelled frame containing the password row + show-password check */
    snprintf(header, sizeof(header),
             _("Password required for \"%s\":"), ssid ?: "network");
    frame = elm_frame_add(dialog->win);
    elm_object_text_set(frame, header);
-   evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, 0);
    evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
 
-   box = elm_box_add(frame);
-   elm_box_horizontal_set(box, EINA_FALSE);
-   elm_box_padding_set(box, 0, 4 * e_scale);
-   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
-   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
-   elm_object_content_set(frame, box);
-   evas_object_show(box);
+   table = elm_table_add(frame);
+   elm_table_padding_set(table, 8 * e_scale, 4 * e_scale);
+   evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, 0);
+   evas_object_size_hint_align_set(table, EVAS_HINT_FILL, 0.0);
+   elm_object_content_set(frame, table);
+   evas_object_show(table);
+   _field_column_min_width_set(table, 1);
 
-   entry = elm_entry_add(box);
+   label = elm_label_add(table);
+   elm_object_text_set(label, _("Password"));
+   evas_object_size_hint_weight_set(label, 0, 0);
+   evas_object_size_hint_align_set(label, 1.0, 0.5);
+   elm_table_pack(table, label, 0, 0, 1, 1);
+   evas_object_show(label);
+
+   entry = elm_entry_add(table);
    elm_entry_single_line_set(entry, EINA_TRUE);
    elm_entry_scrollable_set(entry, EINA_TRUE);
    elm_entry_password_set(entry, EINA_TRUE);
@@ -214,21 +327,21 @@ _dialog_new(E_NM_Agent_Request *req, const char *ssid)
    evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
    evas_object_smart_callback_add(entry, "activated",
                                    _entry_activated_cb, ad);
-   elm_box_pack_end(box, entry);
+   elm_table_pack(table, entry, 1, 0, 1, 1);
    evas_object_show(entry);
    ad->psk_entry = entry;
 
-   check = elm_check_add(box);
+   check = elm_check_add(table);
    elm_object_text_set(check, _("Show password"));
    elm_check_state_set(check, EINA_FALSE);
-   evas_object_size_hint_align_set(check, 0.0, 0.5);
+   evas_object_size_hint_align_set(check, EVAS_HINT_FILL, 0.5);
    evas_object_smart_callback_add(check, "changed",
                                    _show_password_cb, entry);
-   elm_box_pack_end(box, check);
+   elm_table_pack(table, check, 1, 1, 1, 1);
    evas_object_show(check);
 
    evas_object_show(frame);
-   e_dialog_content_set(dialog, frame, 280, 100);
+   e_dialog_content_set(dialog, frame, 0, 0);
    e_dialog_show(dialog);
 
    evas_object_event_callback_add(dialog->bg_object, EVAS_CALLBACK_KEY_DOWN,
@@ -243,12 +356,14 @@ _dialog_new(E_NM_Agent_Request *req, const char *ssid)
 
 static E_NM_Agent_Dialog *
 _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
-                const char *service_type,
+                const char *service_type, const char *message,
                 const char *const *fields, unsigned int n_fields)
 {
    E_NM_Agent_Dialog *ad;
-   Evas_Object *frame, *box;
+   Evas_Object *frame, *box, *table;
    E_Dialog *dialog;
+   Eina_Bool *used = NULL;
+   Evas_Coord minw = 260 * e_scale;
    char header[160];
 
    dialog = e_dialog_new(NULL, "E", "nm_secret_agent_vpn");
@@ -261,10 +376,28 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
    ad->n_fields = n_fields;
    ad->field_names = calloc(n_fields ?: 1, sizeof(*ad->field_names));
    ad->field_entries = calloc(n_fields ?: 1, sizeof(*ad->field_entries));
-   for (unsigned int i = 0; i < n_fields; i++)
-     ad->field_names[i] = strdup(fields[i]);
+   used = calloc(n_fields ?: 1, sizeof(*used));
+   if (!ad->field_names || !ad->field_entries || !used)
+     {
+        free(ad->field_names);
+        free(ad->field_entries);
+        free(used);
+        free(ad);
+        e_object_del(E_OBJECT(dialog));
+        return NULL;
+     }
 
-   e_dialog_resizable_set(dialog, 1);
+   for (unsigned int row = 0; row < n_fields; row++)
+     {
+        int idx = _vpn_field_order_find(fields, n_fields, used);
+
+        if (idx < 0) break;
+        used[idx] = EINA_TRUE;
+        ad->field_names[row] = fields[idx] ? strdup(fields[idx]) : NULL;
+     }
+   free(used);
+
+   e_dialog_resizable_set(dialog, 0);
    e_dialog_title_set(dialog, _("VPN Authentication Required"));
    e_dialog_border_icon_set(dialog, "dialog-password");
    e_dialog_button_add(dialog, _("Connect"), NULL, _dialog_ok_cb, ad);
@@ -275,50 +408,63 @@ _vpn_dialog_new(E_NM_Agent_Request *req, const char *conn_name,
             enm_vpn_type_label(NULL, service_type));
    frame = elm_frame_add(dialog->win);
    elm_object_text_set(frame, header);
-   evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_weight_set(frame, EVAS_HINT_EXPAND, 0);
    evas_object_size_hint_align_set(frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
 
    box = elm_box_add(frame);
    elm_box_horizontal_set(box, EINA_FALSE);
-   elm_box_padding_set(box, 0, 6 * e_scale);
-   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
-   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_padding_set(box, 0, 4 * e_scale);
+   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, 0);
+   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, 0.0);
    elm_object_content_set(frame, box);
    evas_object_show(box);
 
+   if (message && message[0])
+     {
+        Evas_Object *msg = elm_label_add(box);
+        elm_object_text_set(msg, message);
+        evas_object_size_hint_weight_set(msg, EVAS_HINT_EXPAND, 0);
+        evas_object_size_hint_align_set(msg, EVAS_HINT_FILL, 0.5);
+        elm_box_pack_end(box, msg);
+        evas_object_show(msg);
+     }
+
+   table = elm_table_add(box);
+   elm_table_padding_set(table, 8 * e_scale, 4 * e_scale);
+   evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, 0);
+   evas_object_size_hint_align_set(table, EVAS_HINT_FILL, 0.0);
+   elm_box_pack_end(box, table);
+   evas_object_show(table);
+   _field_column_min_width_set(table, 1);
+
    for (unsigned int i = 0; i < n_fields; i++)
      {
-        Evas_Object *row, *label, *entry;
-        row = elm_box_add(box);
-        elm_box_horizontal_set(row, EINA_TRUE);
-        elm_box_padding_set(row, 8 * e_scale, 0);
-        evas_object_size_hint_weight_set(row, EVAS_HINT_EXPAND, 0);
-        evas_object_size_hint_align_set(row, EVAS_HINT_FILL, 0.5);
-        evas_object_show(row);
+        Evas_Object *label, *entry;
+        const char *field = ad->field_names[i];
 
-        label = elm_label_add(row);
-        elm_object_text_set(label, fields[i]);
-        evas_object_size_hint_align_set(label, 0.0, 0.5);
-        elm_box_pack_end(row, label);
+        label = elm_label_add(table);
+        elm_object_text_set(label, _vpn_field_label_get(field));
+        evas_object_size_hint_weight_set(label, 0, 0);
+        evas_object_size_hint_align_set(label, 1.0, 0.5);
+        elm_table_pack(table, label, 0, i, 1, 1);
         evas_object_show(label);
 
-        entry = elm_entry_add(row);
+        entry = elm_entry_add(table);
         elm_entry_single_line_set(entry, EINA_TRUE);
         elm_entry_scrollable_set(entry, EINA_TRUE);
-        elm_entry_password_set(entry, EINA_TRUE);
+        elm_entry_password_set(entry, _vpn_field_is_password(field));
         evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0);
         evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
         evas_object_smart_callback_add(entry, "activated",
                                        _entry_activated_cb, ad);
-        elm_box_pack_end(row, entry);
+        elm_table_pack(table, entry, 1, i, 1, 1);
         evas_object_show(entry);
 
         ad->field_entries[i] = entry;
-        elm_box_pack_end(box, row);
      }
 
    evas_object_show(frame);
-   e_dialog_content_set(dialog, frame, 360, 60 + 32 * n_fields);
+   e_dialog_content_set(dialog, frame, minw, 0);
    e_dialog_show(dialog);
 
    evas_object_event_callback_add(dialog->bg_object, EVAS_CALLBACK_KEY_DOWN,
@@ -374,6 +520,7 @@ _agent_ui_cancel_cb(void *data EINA_UNUSED,
 static void
 _agent_ui_vpn_request_cb(void *data EINA_UNUSED, E_NM_Agent_Request *req,
                          const char *conn_name, const char *service_type,
+                         const char *message,
                          const char *const *fields, unsigned int n_fields)
 {
    if (_current_dialog)
@@ -383,6 +530,7 @@ _agent_ui_vpn_request_cb(void *data EINA_UNUSED, E_NM_Agent_Request *req,
         _current_dialog = NULL;
      }
    _current_dialog = _vpn_dialog_new(req, conn_name, service_type,
+                                     message,
                                      fields, n_fields);
    if (!_current_dialog) { e_nm_agent_reply_cancel(req); return; }
 }
diff --git a/src/modules/networkmanager/e_networkmanager.c b/src/modules/networkmanager/e_networkmanager.c
index 6d62b6580..b7dccbef0 100644
--- a/src/modules/networkmanager/e_networkmanager.c
+++ b/src/modules/networkmanager/e_networkmanager.c
@@ -3044,6 +3044,13 @@ _e_nm_sys_resume_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EI
 #define NM_AGENT_MGR_PATH "/org/freedesktop/NetworkManager/AgentManager"
 #define NM_AGENT_ID       "org.enlightenment.NetworkManager"
 #define AGENT_DATA_KEY    "agent"
+#define NM_SECRET_AGENT_CAPABILITY_VPN_HINTS 0x1
+#define NM_SECRET_TAG_VPN_MSG                 "x-vpn-message:"
+#define NM_SECRET_TAG_DYNAMIC_CHALLENGE       "x-dynamic-challenge:"
+#define NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO  "x-dynamic-challenge-echo:"
+#define NM_SETTING_SECRET_FLAG_AGENT_OWNED    0x1
+#define NM_SETTING_SECRET_FLAG_NOT_SAVED      0x2
+#define NM_SETTING_SECRET_FLAG_NOT_REQUIRED   0x4
 
 struct _E_NM_Agent
 {
@@ -3178,6 +3185,7 @@ e_nm_agent_reply_vpn_secrets(E_NM_Agent_Request *req,
    for (unsigned int i = 0; i < n_fields; i++)
      {
         Eldbus_Message_Iter *kv;
+       printf("NM: reply  hint [%s] [%s]\n", fields[i], values[i]);
         eldbus_message_iter_arguments_append(secrets_array, "{ss}", &kv);
         eldbus_message_iter_basic_append(kv, 's', fields[i] ?: "");
         eldbus_message_iter_basic_append(kv, 's', values[i] ?: "");
@@ -3241,8 +3249,58 @@ struct _Agent_Vpn_Conn_Info
 {
    char *conn_id;
    char *svc_type;
+   Eina_List *vpn_data; /* Agent_Vpn_Data_Item* */
 };
 
+typedef struct _Agent_Vpn_Data_Item
+{
+   char *key;
+   char *value;
+} Agent_Vpn_Data_Item;
+
+static void
+_agent_vpn_data_item_free(Agent_Vpn_Data_Item *item)
+{
+   if (!item) return;
+   free(item->key);
+   free(item->value);
+   free(item);
+}
+
+static void
+_agent_vpn_conn_info_clear(struct _Agent_Vpn_Conn_Info *info)
+{
+   Agent_Vpn_Data_Item *item;
+
+   if (!info) return;
+   free(info->conn_id);
+   free(info->svc_type);
+   EINA_LIST_FREE(info->vpn_data, item)
+     _agent_vpn_data_item_free(item);
+}
+
+static void
+_agent_vpn_data_parse(Eldbus_Message_Iter *data_iter,
+                      struct _Agent_Vpn_Conn_Info *out)
+{
+   Eldbus_Message_Iter *entry;
+
+   while (eldbus_message_iter_get_and_next(data_iter, 'e', &entry))
+     {
+        Agent_Vpn_Data_Item *item;
+        const char *key, *value;
+
+        if (!eldbus_message_iter_arguments_get(entry, "ss", &key, &value))
+          continue;
+
+        item = E_NEW(Agent_Vpn_Data_Item, 1);
+        if (!item) continue;
+        item->key = key ? strdup(key) : NULL;
+        item->value = value ? strdup(value) : NULL;
+        out->vpn_data = eina_list_append(out->vpn_data, item);
+     }
+}
+
 static void
 _agent_vpn_conn_info_parse(Eldbus_Message_Iter *conn_props,
                            struct _Agent_Vpn_Conn_Info *out)
@@ -3251,6 +3309,7 @@ _agent_vpn_conn_info_parse(Eldbus_Message_Iter *conn_props,
 
    out->conn_id = NULL;
    out->svc_type = NULL;
+   out->vpn_data = NULL;
 
    while (eldbus_message_iter_get_and_next(conn_props, 'e', &conn_dict))
      {
@@ -3281,48 +3340,212 @@ _agent_vpn_conn_info_parse(Eldbus_Message_Iter *conn_props,
                   if (eldbus_message_iter_arguments_get(var, "s", &s))
                     out->svc_type = strdup(s);
                }
-          }
-
-        if (out->conn_id && out->svc_type) return;
-     }
-}
-
-static char **
-_agent_hints_extract(Eldbus_Message_Iter *hints, unsigned int *n_out)
-{
-   char **arr = NULL;
-   unsigned int n = 0, cap = 0;
-   const char *s;
-   while (eldbus_message_iter_get_and_next(hints, 's', &s))
-     {
-        /* Always keep room for the trailing NULL sentinel. */
-        if (n + 1 >= cap)
-          {
-             unsigned int new_cap = cap ? cap * 2 : 4;
-             char **tmp = realloc(arr, sizeof(*arr) * new_cap);
-             if (!tmp)
+             else if (want_vpn && !strcmp(ekey, "data"))
                {
-                  for (unsigned int i = 0; i < n; i++) free(arr[i]);
-                  free(arr);
-                  *n_out = 0;
-                  return NULL;
+                  Eldbus_Message_Iter *data_iter;
+
+                  if (eldbus_message_iter_arguments_get(var, "a{ss}",
+                                                        &data_iter))
+                    _agent_vpn_data_parse(data_iter, out);
                }
-             arr = tmp;
-             cap = new_cap;
           }
-        arr[n++] = strdup(s);
+
+        if (out->conn_id && out->svc_type && out->vpn_data) return;
      }
-   if (arr) arr[n] = NULL;
-   *n_out = n;
-   return arr;
 }
 
+static const char *
+_agent_vpn_data_find(const struct _Agent_Vpn_Conn_Info *info,
+                     const char *key)
+{
+   Eina_List *l;
+   Agent_Vpn_Data_Item *item;
+
+   if (!info || !key) return NULL;
+   EINA_LIST_FOREACH(info->vpn_data, l, item)
+     {
+        if (item->key && !strcmp(item->key, key))
+          return item->value;
+     }
+   return NULL;
+}
+
+static Eina_Bool
+_agent_vpn_secret_flags_get(const struct _Agent_Vpn_Conn_Info *info,
+                            const char *secret_name,
+                            unsigned int *flags_out)
+{
+   char key[256];
+   const char *value;
+   char *end = NULL;
+   unsigned long flags;
+
+   if (!secret_name || !secret_name[0]) return EINA_FALSE;
+   snprintf(key, sizeof(key), "%s-flags", secret_name);
+   value = _agent_vpn_data_find(info, key);
+   if (!value) return EINA_FALSE;
+
+   flags = strtoul(value, &end, 10);
+   if (!end || *end) return EINA_FALSE;
+
+   if (flags_out) *flags_out = (unsigned int)flags;
+   return EINA_TRUE;
+}
+
+typedef struct _Agent_Vpn_Field_List
+{
+   char **items;
+   unsigned int len;
+   unsigned int cap;
+   char *message;
+} Agent_Vpn_Field_List;
+
 static void
-_agent_str_array_free(char **arr, unsigned int n)
+_agent_vpn_field_list_clear(Agent_Vpn_Field_List *list)
 {
-   if (!arr) return;
-   for (unsigned int i = 0; i < n; i++) free(arr[i]);
-   free(arr);
+   if (!list) return;
+   for (unsigned int i = 0; i < list->len; i++) free(list->items[i]);
+   free(list->items);
+   free(list->message);
+}
+
+static Eina_Bool
+_agent_vpn_field_list_contains(const Agent_Vpn_Field_List *list,
+                               const char *field)
+{
+   if (!list || !field) return EINA_FALSE;
+   for (unsigned int i = 0; i < list->len; i++)
+     if (list->items[i] && !strcmp(list->items[i], field))
+       return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_agent_vpn_field_list_add(Agent_Vpn_Field_List *list, const char *field)
+{
+   char **tmp;
+   unsigned int new_cap;
+
+   if (!field || !field[0]) return EINA_TRUE;
+   if (_agent_vpn_field_list_contains(list, field)) return EINA_TRUE;
+
+   if (list->len + 1 >= list->cap)
+     {
+        new_cap = list->cap ? list->cap * 2 : 4;
+        tmp = realloc(list->items, sizeof(*list->items) * new_cap);
+        if (!tmp) return EINA_FALSE;
+        list->items = tmp;
+        list->cap = new_cap;
+     }
+
+   list->items[list->len] = strdup(field);
+   if (!list->items[list->len]) return EINA_FALSE;
+   list->len++;
+   list->items[list->len] = NULL;
+   return EINA_TRUE;
+}
+
+static const struct
+{
+   const char *type;
+   const char *name;
+} _agent_vpn_default_secrets[] = {
+   { "pptp",        "password" },
+   { "iodine",      "password" },
+   { "ssh",         "password" },
+   { "l2tp",        "password" },
+   { "fortisslvpn", "password" },
+   { "openvpn",     "password" },
+   { "openvpn",     "cert-pass" },
+   { "openvpn",     "http-proxy-password" },
+   { "vpnc",        "Xauth password" },
+   { "vpnc",        "IPSec secret" },
+   { "openswan",    "xauthpassword" },
+   { "openswan",    "pskvalue" },
+   { "libreswan",   "xauthpassword" },
+   { "libreswan",   "pskvalue" },
+   { "strongswan",  "xauthpassword" },
+   { "strongswan",  "pskvalue" },
+   { "openconnect", "gateway" },
+   { "openconnect", "cookie" },
+   { "openconnect", "gwcert" },
+   { "openconnect", "resolve" },
+   { NULL, NULL }
+};
+
+static const char *
+_agent_vpn_service_short_name(const char *service_type)
+{
+   const char *p;
+
+   if (!service_type) return NULL;
+   p = strrchr(service_type, '.');
+   return p ? p + 1 : service_type;
+}
+
+static Eina_Bool
+_agent_vpn_fields_from_hints(Eldbus_Message_Iter *hints,
+                             Agent_Vpn_Field_List *fields,
+                             Eina_Bool *is_challenge)
+{
+   const char *s;
+
+  printf("NM: hints [%p]\n", hints);
+   if (is_challenge) *is_challenge = EINA_FALSE;
+
+   while (eldbus_message_iter_get_and_next(hints, 's', &s))
+     {
+       printf("NM: hint [%s]\n", s);
+        if (!s) continue;
+        if (!strncmp(s, NM_SECRET_TAG_VPN_MSG, strlen(NM_SECRET_TAG_VPN_MSG)))
+          {
+             free(fields->message);
+             fields->message = strdup(s + strlen(NM_SECRET_TAG_VPN_MSG));
+             if (!fields->message) return EINA_FALSE;
+             continue;
+          }
+        if (!strncmp(s, NM_SECRET_TAG_DYNAMIC_CHALLENGE,
+                     strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE)) ||
+            !strncmp(s, NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO,
+                     strlen(NM_SECRET_TAG_DYNAMIC_CHALLENGE_ECHO)))
+          {
+             if (is_challenge) *is_challenge = EINA_TRUE;
+          }
+        if (!_agent_vpn_field_list_add(fields, s))
+          return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_agent_vpn_fields_add_defaults(const struct _Agent_Vpn_Conn_Info *info,
+                               Agent_Vpn_Field_List *fields)
+{
+   const char *short_name = _agent_vpn_service_short_name(info->svc_type);
+
+   if (!short_name) return EINA_TRUE;
+
+   for (unsigned int i = 0; _agent_vpn_default_secrets[i].type; i++)
+     {
+        unsigned int flags = 0;
+        const char *name = _agent_vpn_default_secrets[i].name;
+
+        if (strcmp(short_name, _agent_vpn_default_secrets[i].type))
+          continue;
+        if (!_agent_vpn_secret_flags_get(info, name, &flags))
+          continue;
+        if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
+          continue;
+        if (!(flags & (NM_SETTING_SECRET_FLAG_AGENT_OWNED |
+                       NM_SETTING_SECRET_FLAG_NOT_SAVED)))
+          continue;
+       printf("NM: hint def [%s]\n", name);
+        if (!_agent_vpn_field_list_add(fields, name))
+          return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
 }
 
 static Eldbus_Message *
@@ -3336,6 +3559,7 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
    uint32_t flags;
    char ssid[64] = "";
 
+  printf("NM: _agent_get_secrets()...\n");
    a = eldbus_service_object_data_get(iface, AGENT_DATA_KEY);
 
    if (!eldbus_message_arguments_get(msg, "a{sa{sv}}osasu",
@@ -3345,6 +3569,7 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
         WRN("GetSecrets: cannot parse arguments");
         return eldbus_message_method_return_new(msg);
      }
+  printf("NM: _agent_get_secrets() 2\n");
 
    DBG("GetSecrets for %s setting=%s flags=%u",
        conn_path, setting_name, flags);
@@ -3370,20 +3595,47 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
    if (!strcmp(setting_name, "vpn"))
      {
         struct _Agent_Vpn_Conn_Info info;
-        unsigned int n_hints = 0;
-        char **hint_arr;
+        Agent_Vpn_Field_List fields = { 0 };
+        Eina_Bool is_challenge = EINA_FALSE;
 
+  printf("NM: _agent_get_secrets() vpn\n");
         /* Single forward pass over the connection dict: both connection.id
          * and vpn.service-type are collected in one walk to avoid the
-         * forward-only iterator skipping the second key. */
+         * forward-only iterator skipping the second key.  vpn.data is also
+         * collected because NM-style agents use it to inspect per-secret
+         * flags when hints are empty or incomplete. */
         _agent_vpn_conn_info_parse(conn_props, &info);
-        hint_arr = _agent_hints_extract(hints, &n_hints);
+
+        if (!_agent_vpn_fields_from_hints(hints, &fields, &is_challenge) ||
+            (!is_challenge &&
+             !_agent_vpn_fields_add_defaults(&info, &fields)))
+          {
+  printf("NM: _agent_get_secrets() clear 1\n");
+             WRN("GetSecrets: failed to build VPN secret request");
+             e_nm_agent_reply_cancel(req);
+             _agent_vpn_field_list_clear(&fields);
+             _agent_vpn_conn_info_clear(&info);
+             return NULL;
+          }
+
+        if (fields.len == 0)
+          {
+  printf("NM: _agent_get_secrets() fields.len == 0\n");
+             WRN("GetSecrets: no VPN secrets requested by hints or flags");
+             e_nm_agent_reply_cancel(req);
+             _agent_vpn_field_list_clear(&fields);
+             _agent_vpn_conn_info_clear(&info);
+             return NULL;
+          }
 
         if (_agent_cbs.vpn_request)
           {
+  printf("NM: _agent_get_secrets() _agent_cbs.vpn_request() [%s] [%p] %i\n", fields.message, fields.items, fields.len);
              _agent_cbs.vpn_request(_agent_cb_data, req,
                                     info.conn_id ?: "VPN", info.svc_type,
-                                    (const char *const *)hint_arr, n_hints);
+                                    fields.message,
+                                    (const char *const *)fields.items,
+                                    fields.len);
           }
         else
           {
@@ -3391,12 +3643,12 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
              e_nm_agent_reply_cancel(req);
           }
 
-        free(info.conn_id);
-        free(info.svc_type);
-        _agent_str_array_free(hint_arr, n_hints);
+        _agent_vpn_field_list_clear(&fields);
+        _agent_vpn_conn_info_clear(&info);
      }
    else if (!strcmp(setting_name, "802-11-wireless-security"))
      {
+  printf("NM: _agent_get_secrets() wifi\n");
         if (_agent_cbs.request)
           _agent_cbs.request(_agent_cb_data, req, ssid[0] ? ssid : NULL);
         else
@@ -3404,6 +3656,7 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
      }
    else
      {
+  printf("NM: _agent_get_secrets() cancel\n");
         WRN("Unhandled secret setting %s; cancelling", setting_name);
         e_nm_agent_reply_cancel(req);
      }
@@ -3537,8 +3790,10 @@ _e_nm_agent_new(Eldbus_Connection *eldbus_conn)
 
    obj   = eldbus_object_get(a->eldbus_conn, NM_BUS_NAME, NM_AGENT_MGR_PATH);
    proxy = eldbus_proxy_get(obj, NM_IFACE_AGENT_MGR);
-   eldbus_proxy_call(proxy, "Register", _agent_register_cb, NULL, -1,
-                     "s", NM_AGENT_ID);
+   eldbus_proxy_call(proxy, "RegisterWithCapabilities",
+                     _agent_register_cb, NULL, -1,
+                     "su", NM_AGENT_ID,
+                     (uint32_t)NM_SECRET_AGENT_CAPABILITY_VPN_HINTS);
    eldbus_proxy_unref(proxy);
    eldbus_object_unref(obj);
 
diff --git a/src/modules/networkmanager/e_networkmanager.h b/src/modules/networkmanager/e_networkmanager.h
index 4142deb19..9ed81d26f 100644
--- a/src/modules/networkmanager/e_networkmanager.h
+++ b/src/modules/networkmanager/e_networkmanager.h
@@ -42,6 +42,7 @@ typedef void (*E_NM_Agent_VPN_Secrets_Request_Cb)(void *data,
         E_NM_Agent_Request *req,
         const char *conn_name,
         const char *service_type,
+        const char *message,
         const char *const *fields,
         unsigned int n_fields);
 

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

Reply via email to