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.