eiwd/src/ui/wifi_auth.c
Pierre-Olivier Mercier 8b3ef2c346 defensive: NULL-check calloc results before dereferencing
Five sites allocated with calloc() and dereferenced the result on the
very next line. Under OOM the module would have segfaulted instead of
degrading. Each site now bails (or sends a Canceled D-Bus error, in
the agent path) when the allocation fails.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:27:44 +07:00

137 lines
4 KiB
C

#include "wifi_auth.h"
#include <stdlib.h>
#include <string.h>
typedef struct _Auth_Ctx
{
Evas_Object *win; /* top-level window hosting the popup */
Evas_Object *popup;
Evas_Object *entry;
Wifi_Auth_Cb cb;
void *data;
Eina_Bool fired;
} Auth_Ctx;
static void
_finish(Auth_Ctx *c, Eina_Bool ok)
{
if (c->fired) return;
c->fired = EINA_TRUE;
/* Copy the passphrase into a buffer we own so we can wipe it
* after the callback returns. The elm_entry's internal buffer
* is then overwritten before the window (and entry) are destroyed. */
char *pass = NULL;
if (ok && c->entry)
{
const char *raw = elm_entry_entry_get(c->entry);
if (raw) pass = strdup(raw);
}
if (c->cb) c->cb(c->data, pass, ok);
if (pass)
{
explicit_bzero(pass, strlen(pass));
free(pass);
}
if (c->entry) elm_entry_entry_set(c->entry, "");
if (c->win) evas_object_del(c->win);
free(c);
}
static void
_on_ok(void *data, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED)
{
_finish(data, EINA_TRUE);
}
static void
_on_cancel(void *data, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED)
{
_finish(data, EINA_FALSE);
}
static void
_on_del(void *data, Evas *e EINA_UNUSED, Evas_Object *o EINA_UNUSED, void *ev EINA_UNUSED)
{
/* Window closed without cancel/ok — treat as cancel. */
Auth_Ctx *c = data;
/* The window (and entry) are being destroyed; null entry to skip the
* post-cb entry_set in _finish. */
c->win = NULL;
c->entry = NULL;
_finish(c, EINA_FALSE);
}
Evas_Object *
wifi_auth_prompt(Evas_Object *parent EINA_UNUSED, const char *ssid,
const char *security,
Wifi_Auth_Cb cb, void *data)
{
Auth_Ctx *c = calloc(1, sizeof(*c));
if (!c) return NULL;
c->cb = cb; c->data = data;
/* A floating top-level window so the popup is actually visible —
* elm_popup parented to a gadcon popup's sub-canvas never shows. */
Evas_Object *win = elm_win_add(NULL, "eiwd-auth", ELM_WIN_DIALOG_BASIC);
elm_win_title_set(win, "iwd Wi-Fi");
elm_win_autodel_set(win, EINA_TRUE);
elm_win_center(win, EINA_TRUE, EINA_TRUE);
evas_object_resize(win, 360, 200);
c->win = win;
Evas_Object *bg = elm_bg_add(win);
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, bg);
evas_object_show(bg);
Evas_Object *p = elm_popup_add(win);
c->popup = p;
char title[256];
snprintf(title, sizeof(title), "Connect to %s", ssid ? ssid : "network");
elm_object_part_text_set(p, "title,text", title);
Evas_Object *box = elm_box_add(p);
elm_box_padding_set(box, 0, 6);
if (security && *security)
{
char buf[128];
snprintf(buf, sizeof(buf), "Security: %s", security);
Evas_Object *lbl = elm_label_add(box);
elm_object_text_set(lbl, buf);
evas_object_size_hint_align_set(lbl, 0.0, 0.5);
elm_box_pack_end(box, lbl);
evas_object_show(lbl);
}
Evas_Object *entry = elm_entry_add(box);
elm_entry_single_line_set(entry, EINA_TRUE);
elm_entry_password_set(entry, EINA_TRUE);
elm_entry_scrollable_set(entry, EINA_TRUE);
evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0);
evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0);
elm_box_pack_end(box, entry);
evas_object_show(entry);
c->entry = entry;
evas_object_show(box);
elm_object_content_set(p, box);
Evas_Object *bcancel = elm_button_add(p);
elm_object_text_set(bcancel, "Cancel");
elm_object_part_content_set(p, "button1", bcancel);
evas_object_smart_callback_add(bcancel, "clicked", _on_cancel, c);
Evas_Object *bok = elm_button_add(p);
elm_object_text_set(bok, "Connect");
elm_object_part_content_set(p, "button2", bok);
evas_object_smart_callback_add(bok, "clicked", _on_ok, c);
evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _on_del, c);
evas_object_show(p);
evas_object_show(win);
elm_object_focus_set(entry, EINA_TRUE);
return win;
}