mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-14 00:02:45 -04:00
feat: retrieve WiFi/VPN secrets from D-Bus Secret Service with unlock support (#2402)
* fix: preserve pre-existing connection profiles on cancelled WiFi activation When a pre-existing WiFi connection activation is cancelled, do not remove the connection profile — only remove profiles for newly created connections. * feat: retrieve WiFi/VPN secrets from D-Bus secret service with unlock Wireless, 802.1x, VPN, and WireGuard secrets are now looked up from org.freedesktop.Secret before prompting the user. If the keyring is locked, the unlock prompt is triggered via Prompt.Prompt() and the lookup retried after the vault is unlocked.
This commit is contained in:
@@ -23,6 +23,13 @@ const (
|
||||
agentIdentifier = "com.danklinux.NMAgent"
|
||||
)
|
||||
|
||||
const (
|
||||
nmSecretAgentFlagAllowInteraction = 0x1
|
||||
nmSecretAgentFlagRequestNew = 0x2
|
||||
nmSecretAgentFlagUserRequested = 0x4
|
||||
nmSecretAgentFlagOnlySystem = 0x80000000
|
||||
)
|
||||
|
||||
type SecretAgent struct {
|
||||
conn *dbus.Conn
|
||||
objPath dbus.ObjectPath
|
||||
@@ -129,6 +136,21 @@ func (a *SecretAgent) GetSecrets(
|
||||
|
||||
log.Infof("[SecretAgent] connType=%s, name=%s, vpnSvc=%s, fields=%v, flags=%d, vpnPasswordFlags=%d", connType, displayName, vpnSvc, fields, flags, vpnPasswordFlags)
|
||||
|
||||
if flags&nmSecretAgentFlagOnlySystem != 0 {
|
||||
log.Infof("[SecretAgent] ONLY_SYSTEM flag set, deferring to system secret storage")
|
||||
return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
|
||||
}
|
||||
|
||||
var connUuid string
|
||||
if c, ok := conn["connection"]; ok {
|
||||
if v, ok := c["uuid"]; ok {
|
||||
if s, ok2 := v.Value().(string); ok2 {
|
||||
connUuid = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 1: Determine if this connection is ours and what fields we need.
|
||||
if a.backend != nil {
|
||||
a.backend.stateMutex.RLock()
|
||||
isConnecting := a.backend.state.IsConnecting
|
||||
@@ -145,15 +167,6 @@ func (a *SecretAgent) GetSecrets(
|
||||
return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
|
||||
}
|
||||
case "vpn", "wireguard":
|
||||
var connUuid string
|
||||
if c, ok := conn["connection"]; ok {
|
||||
if v, ok := c["uuid"]; ok {
|
||||
if s, ok2 := v.Value().(string); ok2 {
|
||||
connUuid = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're connecting to a VPN, only respond if it's the one we're connecting to
|
||||
// This prevents interfering with nmcli/other tools when our app isn't connecting
|
||||
if isConnectingVPN && connUuid != connectingVPNUUID {
|
||||
@@ -163,6 +176,7 @@ func (a *SecretAgent) GetSecrets(
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 2: Resolve fields from hints or password-flags.
|
||||
if len(fields) == 0 {
|
||||
if settingName == "vpn" {
|
||||
if a.backend != nil {
|
||||
@@ -230,41 +244,19 @@ func (a *SecretAgent) GetSecrets(
|
||||
return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
|
||||
}
|
||||
log.Infof("[SecretAgent] Agent-owned secrets, inferred fields: %v", fields)
|
||||
} else if passwordFlags&NM_SETTING_SECRET_FLAG_NOT_SAVED != 0 {
|
||||
log.Infof("[SecretAgent] Secrets not saved, will need to prompt (flags=%d)", passwordFlags)
|
||||
// Fall through — fields remain empty, prompt will be required.
|
||||
} else {
|
||||
log.Infof("[SecretAgent] No secrets needed, using system stored secrets (flags=%d)", passwordFlags)
|
||||
out := nmSettingMap{}
|
||||
out[settingName] = nmVariantMap{}
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reason := reasonFromFlags(flags)
|
||||
if a.manager != nil && connType == "802-11-wireless" && a.manager.WasRecentlyFailed(ssid) {
|
||||
reason = "wrong-password"
|
||||
}
|
||||
if settingName == "vpn" && isPKCS11Auth(conn, vpnSvc) {
|
||||
reason = "pkcs11"
|
||||
}
|
||||
|
||||
var connId, connUuid string
|
||||
if c, ok := conn["connection"]; ok {
|
||||
if v, ok := c["id"]; ok {
|
||||
if s, ok2 := v.Value().(string); ok2 {
|
||||
connId = s
|
||||
}
|
||||
}
|
||||
if v, ok := c["uuid"]; ok {
|
||||
if s, ok2 := v.Value().(string); ok2 {
|
||||
connUuid = s
|
||||
log.Infof("[SecretAgent] Secrets stored in NM config (flags=%d), deferring to system", passwordFlags)
|
||||
return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 3: Cached VPN credentials — user-provided, take priority.
|
||||
if settingName == "vpn" && a.backend != nil {
|
||||
// Check for cached PKCS11 PIN first
|
||||
isPKCS11Request := len(fields) == 1 && fields[0] == "key_pass"
|
||||
if isPKCS11Request {
|
||||
if isPKCS11Request := len(fields) == 1 && fields[0] == "key_pass"; isPKCS11Request {
|
||||
a.backend.cachedPKCS11Mu.Lock()
|
||||
cached := a.backend.cachedPKCS11PIN
|
||||
if cached != nil && cached.ConnectionUUID == connUuid {
|
||||
@@ -283,7 +275,6 @@ func (a *SecretAgent) GetSecrets(
|
||||
a.backend.cachedPKCS11Mu.Unlock()
|
||||
}
|
||||
|
||||
// Check for cached VPN password
|
||||
a.backend.cachedVPNCredsMu.Lock()
|
||||
cached := a.backend.cachedVPNCreds
|
||||
if cached != nil && cached.ConnectionUUID == connUuid {
|
||||
@@ -314,6 +305,7 @@ func (a *SecretAgent) GetSecrets(
|
||||
a.backend.cachedGPSamlMu.Lock()
|
||||
cachedGPSaml := a.backend.cachedGPSamlCookie
|
||||
if cachedGPSaml != nil && cachedGPSaml.ConnectionUUID == connUuid {
|
||||
a.backend.cachedGPSamlCookie = nil
|
||||
a.backend.cachedGPSamlMu.Unlock()
|
||||
|
||||
log.Infof("[SecretAgent] Using cached GlobalProtect SAML cookie for %s", connUuid)
|
||||
@@ -369,6 +361,37 @@ func (a *SecretAgent) GetSecrets(
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 4: Non-interactive secret retrieval (keyring).
|
||||
// Always try the keyring even when REQUEST_NEW is set — the vault may have
|
||||
// been unlocked by a prior call's Prompt flow, making the lookup non-interactive.
|
||||
if secretOut := a.trySecretService(connUuid, settingName, fields); secretOut != nil {
|
||||
return secretOut, nil
|
||||
}
|
||||
|
||||
// Phase 5: If interaction is not allowed, we're done.
|
||||
if flags&nmSecretAgentFlagAllowInteraction == 0 {
|
||||
log.Infof("[SecretAgent] ALLOW_INTERACTION not set, cannot prompt user")
|
||||
return nil, dbus.NewError("org.freedesktop.NetworkManager.SecretAgent.Error.NoSecrets", nil)
|
||||
}
|
||||
|
||||
// Phase 6: Prepare prompt.
|
||||
reason := reasonFromFlags(flags)
|
||||
if a.manager != nil && connType == "802-11-wireless" && a.manager.WasRecentlyFailed(ssid) {
|
||||
reason = "wrong-password"
|
||||
}
|
||||
if settingName == "vpn" && isPKCS11Auth(conn, vpnSvc) {
|
||||
reason = "pkcs11"
|
||||
}
|
||||
|
||||
var connId string
|
||||
if c, ok := conn["connection"]; ok {
|
||||
if v, ok := c["id"]; ok {
|
||||
if s, ok2 := v.Value().(string); ok2 {
|
||||
connId = s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
@@ -403,6 +426,7 @@ func (a *SecretAgent) GetSecrets(
|
||||
wasConnectingVPN := a.backend.state.IsConnectingVPN
|
||||
cancelledSSID := a.backend.state.ConnectingSSID
|
||||
cancelledVPNUUID := a.backend.state.ConnectingVPNUUID
|
||||
connPreExisting := a.backend.state.ConnectingPreExisting
|
||||
if wasConnecting || wasConnectingVPN {
|
||||
log.Infof("[SecretAgent] Clearing connecting state due to cancelled prompt")
|
||||
a.backend.state.IsConnecting = false
|
||||
@@ -414,7 +438,8 @@ func (a *SecretAgent) GetSecrets(
|
||||
|
||||
// If this was a WiFi connection that was just cancelled, remove the connection profile
|
||||
// (it was created with AddConnection but activation was cancelled)
|
||||
if wasConnecting && cancelledSSID != "" && connType == "802-11-wireless" {
|
||||
// Only do this for newly created connections, not pre-existing ones.
|
||||
if wasConnecting && cancelledSSID != "" && connType == "802-11-wireless" && !connPreExisting {
|
||||
log.Infof("[SecretAgent] Removing connection profile for cancelled WiFi connection: %s", cancelledSSID)
|
||||
if err := a.backend.ForgetWiFiNetwork(cancelledSSID); err != nil {
|
||||
log.Warnf("[SecretAgent] Failed to remove cancelled connection profile: %v", err)
|
||||
@@ -623,7 +648,7 @@ func fieldsNeeded(setting string, hints []string, conn map[string]nmVariantMap)
|
||||
return hints
|
||||
}
|
||||
return infer8021xFields(conn)
|
||||
case "vpn":
|
||||
case "vpn", "wireguard":
|
||||
return hints
|
||||
default:
|
||||
return []string{}
|
||||
|
||||
@@ -339,6 +339,41 @@ func TestInferVPNFields_GPSaml(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretAgent_GetSecrets_OnlySystemFlag(t *testing.T) {
|
||||
agent := &SecretAgent{}
|
||||
conn := map[string]nmVariantMap{
|
||||
"connection": {
|
||||
"id": dbus.MakeVariant("TestWiFi"),
|
||||
"type": dbus.MakeVariant("802-11-wireless"),
|
||||
},
|
||||
"802-11-wireless": {
|
||||
"ssid": dbus.MakeVariant("TestSSID"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := agent.GetSecrets(conn, "/test/path", "802-11-wireless-security", nil, 0x80000000)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "NoSecrets")
|
||||
}
|
||||
|
||||
func TestSecretAgent_GetSecrets_NoInteractionFlag(t *testing.T) {
|
||||
agent := &SecretAgent{}
|
||||
conn := map[string]nmVariantMap{
|
||||
"connection": {
|
||||
"id": dbus.MakeVariant("TestWiFi"),
|
||||
"type": dbus.MakeVariant("802-11-wireless"),
|
||||
},
|
||||
"802-11-wireless": {
|
||||
"ssid": dbus.MakeVariant("TestSSID"),
|
||||
},
|
||||
}
|
||||
|
||||
// flags=0 means ALLOW_INTERACTION is not set
|
||||
_, err := agent.GetSecrets(conn, "/test/path", "802-11-wireless-security", nil, 0x0)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "NoSecrets")
|
||||
}
|
||||
|
||||
func TestNmVariantMap(t *testing.T) {
|
||||
// Test that nmVariantMap and nmSettingMap work correctly
|
||||
settingMap := make(nmSettingMap)
|
||||
|
||||
@@ -74,6 +74,7 @@ type BackendState struct {
|
||||
IsConnecting bool
|
||||
ConnectingSSID string
|
||||
ConnectingDevice string
|
||||
ConnectingPreExisting bool
|
||||
IsConnectingVPN bool
|
||||
ConnectingVPNUUID string
|
||||
LastError string
|
||||
|
||||
@@ -245,18 +245,34 @@ func (b *NetworkManagerBackend) GetWiFiQRCodeContent(ssid string) (string, error
|
||||
return "", fmt.Errorf("QR code generation only supports WPA connections, `%s` uses %s", ssid, securityType)
|
||||
}
|
||||
|
||||
var psk string
|
||||
|
||||
secrets, err := conn.GetSecrets("802-11-wireless-security")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve connection secrets for `%s`: %w", ssid, err)
|
||||
log.Debugf("[GetWiFiQRCodeContent] conn.GetSecrets failed: %v, falling back to secret service", err)
|
||||
} else if secSecrets, ok := secrets["802-11-wireless-security"]; ok {
|
||||
if s, ok := secSecrets["psk"].(string); ok {
|
||||
psk = s
|
||||
}
|
||||
}
|
||||
|
||||
secSecrets, ok := secrets["802-11-wireless-security"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("failed to retrieve password for `%s`", ssid)
|
||||
if psk == "" {
|
||||
uuid := ""
|
||||
if connMeta, ok := connSettings["connection"]; ok {
|
||||
if u, ok := connMeta["uuid"].(string); ok {
|
||||
uuid = u
|
||||
}
|
||||
}
|
||||
if uuid != "" {
|
||||
sess, err := openSecretService()
|
||||
if err == nil {
|
||||
psk = sess.lookup(uuid, "802-11-wireless-security", "psk")
|
||||
sess.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
psk, ok := secSecrets["psk"].(string)
|
||||
if !ok {
|
||||
if psk == "" {
|
||||
return "", fmt.Errorf("failed to retrieve password for `%s`", ssid)
|
||||
}
|
||||
|
||||
@@ -281,6 +297,7 @@ func (b *NetworkManagerBackend) ConnectWiFi(req ConnectionRequest) error {
|
||||
b.state.IsConnecting = true
|
||||
b.state.ConnectingSSID = req.SSID
|
||||
b.state.ConnectingDevice = req.Device
|
||||
b.state.ConnectingPreExisting = false
|
||||
b.state.LastError = ""
|
||||
b.stateMutex.Unlock()
|
||||
|
||||
@@ -292,6 +309,9 @@ func (b *NetworkManagerBackend) ConnectWiFi(req ConnectionRequest) error {
|
||||
|
||||
existingConn, err := b.findConnection(req.SSID)
|
||||
if err == nil && existingConn != nil {
|
||||
b.stateMutex.Lock()
|
||||
b.state.ConnectingPreExisting = true
|
||||
b.stateMutex.Unlock()
|
||||
_, err := nm.ActivateConnection(existingConn, devInfo.device, nil)
|
||||
if err != nil {
|
||||
log.Warnf("[ConnectWiFi] Failed to activate existing connection: %v", err)
|
||||
@@ -607,6 +627,7 @@ func (b *NetworkManagerBackend) findConnection(ssid string) (gonetworkmanager.Co
|
||||
if bytes.Equal(candidateSSID, ssidBytes) {
|
||||
return conn, nil
|
||||
}
|
||||
log.Debugf("[findConnection] SSID mismatch: stored=%q, request=%q", string(candidateSSID), ssid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||
"github.com/godbus/dbus/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
secretServiceBusName = "org.freedesktop.secrets"
|
||||
secretServicePath = "/org/freedesktop/secrets"
|
||||
secretServiceIface = "org.freedesktop.Secret.Service"
|
||||
secretItemIface = "org.freedesktop.Secret.Item"
|
||||
secretPromptIface = "org.freedesktop.Secret.Prompt"
|
||||
)
|
||||
|
||||
type secretServiceSession struct {
|
||||
conn *dbus.Conn
|
||||
svc dbus.BusObject
|
||||
sessionPath dbus.ObjectPath
|
||||
}
|
||||
|
||||
func openSecretService() (*secretServiceSession, error) {
|
||||
c, err := dbus.ConnectSessionBus()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
svc := c.Object(secretServiceBusName, dbus.ObjectPath(secretServicePath))
|
||||
|
||||
var sessionPath dbus.ObjectPath
|
||||
call := svc.Call(secretServiceIface+".OpenSession", 0, "plain", dbus.MakeVariant(""))
|
||||
if call.Err != nil {
|
||||
c.Close()
|
||||
return nil, call.Err
|
||||
}
|
||||
if err := call.Store(new(dbus.Variant), &sessionPath); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &secretServiceSession{
|
||||
conn: c,
|
||||
svc: svc,
|
||||
sessionPath: sessionPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *secretServiceSession) unlock(items []dbus.ObjectPath) error {
|
||||
var prompt dbus.ObjectPath
|
||||
var unlocked []dbus.ObjectPath
|
||||
call := s.svc.Call(secretServiceIface+".Unlock", 0, items)
|
||||
if call.Err != nil {
|
||||
return call.Err
|
||||
}
|
||||
if err := call.Store(&unlocked, &prompt); err != nil {
|
||||
return err
|
||||
}
|
||||
if prompt == "/" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := s.conn.AddMatchSignal(
|
||||
dbus.WithMatchInterface(secretPromptIface),
|
||||
dbus.WithMatchObjectPath(prompt),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
defer s.conn.RemoveMatchSignal(
|
||||
dbus.WithMatchInterface(secretPromptIface),
|
||||
dbus.WithMatchObjectPath(prompt),
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
|
||||
defer cancel()
|
||||
|
||||
ch := make(chan *dbus.Signal, 10)
|
||||
s.conn.Signal(ch)
|
||||
|
||||
go func() {
|
||||
defer s.conn.RemoveSignal(ch)
|
||||
for {
|
||||
select {
|
||||
case v := <-ch:
|
||||
if v.Path == prompt && v.Name == secretPromptIface+".Completed" {
|
||||
if len(v.Body) < 2 {
|
||||
log.Debugf("[SecretAgent] Unlock prompt Completed signal has %d body element(s), expected >= 2", len(v.Body))
|
||||
} else {
|
||||
if dismissed, ok := v.Body[0].(bool); ok && dismissed {
|
||||
log.Debugf("[SecretAgent] Unlock prompt dismissed by user")
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
promptObj := s.conn.Object(secretServiceBusName, prompt)
|
||||
if err := promptObj.Call(secretPromptIface+".Prompt", 0, "").Store(); err != nil {
|
||||
cancel()
|
||||
return err
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
promptObj.Call(secretPromptIface+".Dismiss", 0)
|
||||
return fmt.Errorf("timed out waiting for unlock prompt")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *secretServiceSession) lookup(connUuid, settingName, settingKey string) string {
|
||||
attrs := map[string]string{
|
||||
"connection-uuid": connUuid,
|
||||
"setting-name": settingName,
|
||||
"setting-key": settingKey,
|
||||
}
|
||||
|
||||
var unlocked []dbus.ObjectPath
|
||||
var locked []dbus.ObjectPath
|
||||
call := s.svc.Call(secretServiceIface+".SearchItems", 0, attrs)
|
||||
if call.Err != nil {
|
||||
log.Debugf("[SecretAgent] Secret service SearchItems failed: %v", call.Err)
|
||||
return ""
|
||||
}
|
||||
if err := call.Store(&unlocked, &locked); err != nil {
|
||||
log.Debugf("[SecretAgent] Failed to store SearchItems result: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(unlocked) == 0 && len(locked) > 0 {
|
||||
log.Debugf("[SecretAgent] Attempting to unlock %d locked item(s) for %s", len(locked), connUuid)
|
||||
if err := s.unlock(locked); err != nil {
|
||||
log.Debugf("[SecretAgent] Failed to unlock items: %v", err)
|
||||
return ""
|
||||
}
|
||||
unlocked = locked
|
||||
}
|
||||
|
||||
if len(unlocked) == 0 {
|
||||
log.Debugf("[SecretAgent] No secret service items found for %s", connUuid)
|
||||
return ""
|
||||
}
|
||||
|
||||
item := s.conn.Object(secretServiceBusName, unlocked[0])
|
||||
var secret struct {
|
||||
Session dbus.ObjectPath
|
||||
Parameters []byte
|
||||
Value []byte
|
||||
ContentType string
|
||||
}
|
||||
call = item.Call(secretItemIface+".GetSecret", 0, s.sessionPath)
|
||||
if call.Err != nil {
|
||||
log.Debugf("[SecretAgent] Secret service GetSecret failed: %v", call.Err)
|
||||
return ""
|
||||
}
|
||||
if err := call.Store(&secret); err != nil {
|
||||
log.Debugf("[SecretAgent] Failed to store GetSecret result: %v", err)
|
||||
return ""
|
||||
}
|
||||
|
||||
secretValue := string(secret.Value)
|
||||
if secretValue == "" {
|
||||
log.Debugf("[SecretAgent] Secret service returned empty value for %s/%s", connUuid, settingKey)
|
||||
return ""
|
||||
}
|
||||
|
||||
log.Infof("[SecretAgent] Retrieved secret from secret service for %s/%s", connUuid, settingKey)
|
||||
return secretValue
|
||||
}
|
||||
|
||||
func (s *secretServiceSession) close() {
|
||||
s.conn.Close()
|
||||
}
|
||||
|
||||
func (a *SecretAgent) trySecretService(
|
||||
connUuid string,
|
||||
settingName string,
|
||||
fields []string,
|
||||
) nmSettingMap {
|
||||
if connUuid == "" {
|
||||
log.Debugf("[SecretAgent] trySecretService: connUuid is empty, skipping keyring lookup")
|
||||
return nil
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
log.Debugf("[SecretAgent] trySecretService: no fields requested, skipping keyring lookup")
|
||||
return nil
|
||||
}
|
||||
|
||||
switch settingName {
|
||||
case "802-11-wireless-security", "802-1x", "vpn", "wireguard":
|
||||
default:
|
||||
log.Debugf("[SecretAgent] trySecretService: setting %s not supported for keyring lookup", settingName)
|
||||
return nil
|
||||
}
|
||||
|
||||
sess, err := openSecretService()
|
||||
if err != nil {
|
||||
log.Debugf("[SecretAgent] Failed to open secret service session: %v", err)
|
||||
return nil
|
||||
}
|
||||
defer sess.close()
|
||||
|
||||
found := make(map[string]string)
|
||||
for _, field := range fields {
|
||||
val := sess.lookup(connUuid, settingName, field)
|
||||
if val == "" {
|
||||
log.Debugf("[SecretAgent] Secret service missing field '%s' for %s", field, connUuid)
|
||||
return nil
|
||||
}
|
||||
found[field] = val
|
||||
}
|
||||
|
||||
out := nmSettingMap{}
|
||||
sec := nmVariantMap{}
|
||||
for k, v := range found {
|
||||
sec[k] = dbus.MakeVariant(v)
|
||||
}
|
||||
|
||||
switch settingName {
|
||||
case "vpn":
|
||||
secretsDict := make(map[string]string)
|
||||
for k, v := range found {
|
||||
if k != "username" {
|
||||
secretsDict[k] = v
|
||||
}
|
||||
}
|
||||
vpnSec := nmVariantMap{}
|
||||
vpnSec["secrets"] = dbus.MakeVariant(secretsDict)
|
||||
out[settingName] = vpnSec
|
||||
log.Infof("[SecretAgent] Returning VPN secrets from secret service with %d fields", len(secretsDict))
|
||||
case "802-1x":
|
||||
secretsOnly := nmVariantMap{}
|
||||
for k, v := range found {
|
||||
switch k {
|
||||
case "password", "private-key-password", "phase2-private-key-password", "pin":
|
||||
secretsOnly[k] = dbus.MakeVariant(v)
|
||||
}
|
||||
}
|
||||
out[settingName] = secretsOnly
|
||||
log.Infof("[SecretAgent] Returning 802-1x secrets from secret service with %d fields", len(secretsOnly))
|
||||
default:
|
||||
out[settingName] = sec
|
||||
log.Infof("[SecretAgent] Returning %s secrets from secret service", settingName)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user