mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-07 07:53:18 +02:00
confd: add wifi passphrase and key validation to SR_EV_CHANGE
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
* configuration (hostapd) is handled by hardware.c.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <srx/lyx.h>
|
||||
#include <srx/srx_val.h>
|
||||
|
||||
@@ -16,6 +18,65 @@
|
||||
#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant-%s.conf"
|
||||
|
||||
|
||||
int wifi_validate_secret(sr_session_ctx_t *session, struct lyd_node *cif)
|
||||
{
|
||||
struct lyd_node *wifi, *station, *security, *secret_node;
|
||||
const char *ifname, *secret_name, *security_mode, *b64;
|
||||
unsigned char *decoded;
|
||||
size_t len;
|
||||
|
||||
ifname = lydx_get_cattr(cif, "name");
|
||||
wifi = lydx_get_child(cif, "wifi");
|
||||
if (!wifi)
|
||||
return SR_ERR_OK;
|
||||
|
||||
station = lydx_get_child(wifi, "station");
|
||||
if (!station)
|
||||
return SR_ERR_OK;
|
||||
|
||||
security = lydx_get_child(station, "security");
|
||||
security_mode = lydx_get_cattr(security, "mode");
|
||||
secret_name = lydx_get_cattr(security, "secret");
|
||||
|
||||
if (!secret_name || !strcmp(security_mode, "disabled"))
|
||||
return SR_ERR_OK;
|
||||
|
||||
secret_node = lydx_get_xpathf(cif,
|
||||
"../../keystore/symmetric-keys/symmetric-key[name='%s']",
|
||||
secret_name);
|
||||
b64 = lydx_get_cattr(secret_node, "cleartext-symmetric-key");
|
||||
if (!b64 || !*b64)
|
||||
return SR_ERR_OK;
|
||||
|
||||
decoded = base64_decode((const unsigned char *)b64, strlen(b64), &len);
|
||||
if (!decoded)
|
||||
return SR_ERR_OK;
|
||||
|
||||
if (len < 8 || len > 63) {
|
||||
if (session)
|
||||
sr_session_set_error_message(session,
|
||||
"%s: WiFi passphrase must be 8-63 characters, got %zu",
|
||||
ifname, len);
|
||||
free(decoded);
|
||||
return SR_ERR_VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (!isprint((unsigned char)decoded[i])) {
|
||||
if (session)
|
||||
sr_session_set_error_message(session,
|
||||
"%s: WiFi passphrase contains non-printable "
|
||||
"character at position %zu",
|
||||
ifname, i + 1);
|
||||
free(decoded);
|
||||
return SR_ERR_VALIDATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
free(decoded);
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
wifi_mode_t wifi_get_mode(struct lyd_node *iface)
|
||||
{
|
||||
struct lyd_node *ap, *wifi;
|
||||
|
||||
@@ -2,9 +2,81 @@
|
||||
#include <srx/lyx.h>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "base64.h"
|
||||
|
||||
#define WIREGUARD_CONFIG "/run/wireguard-%s.conf"
|
||||
|
||||
static int wireguard_validate_psk(sr_session_ctx_t *session, struct lyd_node *cif,
|
||||
const char *ifname, const char *psk_ref)
|
||||
{
|
||||
struct lyd_node *psk_node;
|
||||
const char *psk_data;
|
||||
unsigned char *decoded;
|
||||
size_t len;
|
||||
|
||||
psk_node = lydx_get_xpathf(cif,
|
||||
"../../keystore/symmetric-keys/symmetric-key[name='%s']",
|
||||
psk_ref);
|
||||
if (!psk_node)
|
||||
return SR_ERR_OK;
|
||||
|
||||
psk_data = lydx_get_cattr(psk_node, "cleartext-symmetric-key");
|
||||
if (!psk_data || !*psk_data)
|
||||
return SR_ERR_OK;
|
||||
|
||||
decoded = base64_decode((const unsigned char *)psk_data, strlen(psk_data), &len);
|
||||
if (!decoded)
|
||||
return SR_ERR_OK;
|
||||
|
||||
if (len != 32) {
|
||||
if (session)
|
||||
sr_session_set_error_message(session,
|
||||
"%s: WireGuard preshared key '%s' must be "
|
||||
"exactly 32 bytes, got %zu",
|
||||
ifname, psk_ref, len);
|
||||
free(decoded);
|
||||
return SR_ERR_VALIDATION_FAILED;
|
||||
}
|
||||
|
||||
free(decoded);
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
int wireguard_validate_peers(sr_session_ctx_t *session, struct lyd_node *cif)
|
||||
{
|
||||
const char *ifname = lydx_get_cattr(cif, "name");
|
||||
struct lyd_node *wg, *bag_peer, *peer;
|
||||
|
||||
wg = lydx_get_child(cif, "wireguard");
|
||||
if (!wg)
|
||||
return SR_ERR_OK;
|
||||
|
||||
LYX_LIST_FOR_EACH(lyd_child(wg), bag_peer, "peers") {
|
||||
const char *psk_ref;
|
||||
int rc;
|
||||
|
||||
/* Validate bag-level PSK */
|
||||
psk_ref = lydx_get_cattr(bag_peer, "preshared-key");
|
||||
if (psk_ref) {
|
||||
rc = wireguard_validate_psk(session, cif, ifname, psk_ref);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Validate per-peer PSK overrides */
|
||||
LYX_LIST_FOR_EACH(lyd_child(bag_peer), peer, "peer") {
|
||||
psk_ref = lydx_get_cattr(peer, "preshared-key");
|
||||
if (psk_ref) {
|
||||
rc = wireguard_validate_psk(session, cif, ifname, psk_ref);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
/* Helper to get a peer setting with override logic:
|
||||
* 1. Check peer-specific override
|
||||
* 2. Fall back to key-bag level default
|
||||
|
||||
@@ -391,9 +391,11 @@ static int netdag_gen_afspec_add(sr_session_ctx_t *session, struct dagger *net,
|
||||
case IFT_VXLAN:
|
||||
return vxlan_gen(NULL, cif, ip);
|
||||
case IFT_WIFI:
|
||||
return wifi_add_iface(cif, net);
|
||||
return wifi_validate_secret(session, cif)
|
||||
? : wifi_add_iface(cif, net);
|
||||
case IFT_WIREGUARD:
|
||||
return wireguard_gen(NULL, cif, ip, net);
|
||||
return wireguard_validate_peers(session, cif)
|
||||
? : wireguard_gen(NULL, cif, ip, net);
|
||||
case IFT_ETH:
|
||||
return netdag_gen_ethtool(net, cif, dif);
|
||||
case IFT_LO:
|
||||
@@ -424,7 +426,8 @@ static int netdag_gen_afspec_set(sr_session_ctx_t *session, struct dagger *net,
|
||||
return netdag_gen_ethtool(net, cif, dif);
|
||||
case IFT_WIFI:
|
||||
if (wifi_get_mode(cif) == wifi_station)
|
||||
return wifi_gen_station(cif);
|
||||
return wifi_validate_secret(session, cif)
|
||||
? : wifi_gen_station(cif);
|
||||
return 0;
|
||||
case IFT_DUMMY:
|
||||
case IFT_GRE:
|
||||
@@ -819,6 +822,39 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int interfaces_validate_keys(sr_session_ctx_t *session, struct lyd_node *config)
|
||||
{
|
||||
struct lyd_node *ifaces, *iface;
|
||||
int rc;
|
||||
|
||||
ifaces = lydx_get_descendant(config, "interfaces", "interface", NULL);
|
||||
LYX_LIST_FOR_EACH(ifaces, iface, "interface") {
|
||||
const char *ifname = lydx_get_cattr(iface, "name");
|
||||
|
||||
switch (iftype_from_iface(iface)) {
|
||||
case IFT_WIFI:
|
||||
rc = wifi_validate_secret(session, iface);
|
||||
break;
|
||||
case IFT_WIREGUARD:
|
||||
rc = wireguard_validate_peers(session, iface);
|
||||
break;
|
||||
default:
|
||||
rc = SR_ERR_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
continue;
|
||||
|
||||
if (session)
|
||||
return rc;
|
||||
|
||||
ERROR("%s: key fails validation, check keystore", ifname);
|
||||
}
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
int interfaces_get_all_l3(const struct lyd_node *tree, char ***ifaces)
|
||||
{
|
||||
struct lyd_node *interfaces, *cif;
|
||||
|
||||
@@ -105,6 +105,7 @@ const char *get_chassis_addr(void);
|
||||
int interface_get_phys_addr(struct lyd_node *cif, char *mac);
|
||||
int link_gen_address(struct lyd_node *cif, FILE *ip);
|
||||
int interfaces_get_all_l3(const struct lyd_node *tree, char ***ifaces);
|
||||
int interfaces_validate_keys(sr_session_ctx_t *session, struct lyd_node *config);
|
||||
|
||||
/* ip.c */
|
||||
int netdag_gen_ipv6_autoconf(struct dagger *net, struct lyd_node *cif,
|
||||
@@ -130,6 +131,7 @@ typedef enum wifi_mode_t {
|
||||
wifi_unknown
|
||||
} wifi_mode_t;
|
||||
|
||||
int wifi_validate_secret(sr_session_ctx_t *session, struct lyd_node *cif);
|
||||
int wifi_add_iface(struct lyd_node *cif, struct dagger *net);
|
||||
int wifi_del_iface(struct lyd_node *dif, struct dagger *net);
|
||||
int wifi_mode_changed(struct lyd_node *wifi);
|
||||
@@ -162,6 +164,7 @@ int ifchange_cand_infer_dhcp(sr_session_ctx_t *session, const char *path);
|
||||
int vxlan_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip);
|
||||
|
||||
/* infix-if-wireguard */
|
||||
int wireguard_validate_peers(sr_session_ctx_t *session, struct lyd_node *cif);
|
||||
int wireguard_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip, struct dagger *net);
|
||||
|
||||
#endif /* CONFD_INTERFACES_H_ */
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
|
||||
#include "base64.h"
|
||||
#include "core.h"
|
||||
#include "interfaces.h"
|
||||
|
||||
#define XPATH_KEYSTORE_ "/ietf-keystore:keystore/asymmetric-keys"
|
||||
#define XPATH_KEYSTORE_ASYM "/ietf-keystore:keystore/asymmetric-keys"
|
||||
#define XPATH_KEYSTORE_SYM "/ietf-keystore:keystore/symmetric-keys"
|
||||
#define SSH_PRIVATE_KEY "/tmp/ssh.key"
|
||||
#define SSH_PUBLIC_KEY "/tmp/ssh.pub"
|
||||
|
||||
@@ -166,7 +168,8 @@ int keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
|
||||
struct lyd_node *changes, *change;
|
||||
int rc = SR_ERR_OK;
|
||||
|
||||
if (diff && !lydx_find_xpathf(diff, XPATH_KEYSTORE_))
|
||||
if (diff && !lydx_find_xpathf(diff, XPATH_KEYSTORE_ASYM)
|
||||
&& !lydx_find_xpathf(diff, XPATH_KEYSTORE_SYM))
|
||||
return SR_ERR_OK;
|
||||
|
||||
switch (event) {
|
||||
@@ -174,6 +177,9 @@ int keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
|
||||
rc = keystore_update(session, config, diff);
|
||||
break;
|
||||
case SR_EV_CHANGE:
|
||||
if (diff && lydx_find_xpathf(diff, XPATH_KEYSTORE_SYM))
|
||||
rc = interfaces_validate_keys(session, config);
|
||||
break;
|
||||
case SR_EV_ENABLED:
|
||||
break;
|
||||
case SR_EV_ABORT:
|
||||
@@ -186,6 +192,8 @@ int keystore_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
|
||||
if (rename(SSH_HOSTKEYS_NEXT, SSH_HOSTKEYS))
|
||||
ERRNO("Failed switching to new %s", SSH_HOSTKEYS);
|
||||
}
|
||||
if (diff && lydx_find_xpathf(diff, XPATH_KEYSTORE_SYM))
|
||||
interfaces_validate_keys(NULL, config);
|
||||
return SR_ERR_OK;
|
||||
default:
|
||||
return SR_ERR_OK;
|
||||
|
||||
Reference in New Issue
Block a user