170 lines
5.1 KiB
Go
170 lines
5.1 KiB
Go
package iwd
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/godbus/dbus/v5"
|
|
"github.com/godbus/dbus/v5/introspect"
|
|
)
|
|
|
|
const agentIntrospectXML = `
|
|
<node>
|
|
<interface name="net.connman.iwd.Agent">
|
|
<method name="Release">
|
|
</method>
|
|
<method name="RequestPassphrase">
|
|
<arg name="network" type="o" direction="in"/>
|
|
<arg name="passphrase" type="s" direction="out"/>
|
|
</method>
|
|
<method name="RequestPrivateKeyPassphrase">
|
|
<arg name="network" type="o" direction="in"/>
|
|
<arg name="passphrase" type="s" direction="out"/>
|
|
</method>
|
|
<method name="RequestUserNameAndPassword">
|
|
<arg name="network" type="o" direction="in"/>
|
|
<arg name="username" type="s" direction="out"/>
|
|
<arg name="password" type="s" direction="out"/>
|
|
</method>
|
|
<method name="RequestUserPassword">
|
|
<arg name="network" type="o" direction="in"/>
|
|
<arg name="user" type="s" direction="in"/>
|
|
<arg name="password" type="s" direction="out"/>
|
|
</method>
|
|
<method name="Cancel">
|
|
<arg name="reason" type="s" direction="in"/>
|
|
</method>
|
|
</interface>
|
|
<interface name="org.freedesktop.DBus.Introspectable">
|
|
<method name="Introspect">
|
|
<arg name="xml" type="s" direction="out"/>
|
|
</method>
|
|
</interface>
|
|
</node>`
|
|
|
|
// Agent implements the net.connman.iwd.Agent interface for credential callbacks
|
|
type Agent struct {
|
|
conn *dbus.Conn
|
|
path dbus.ObjectPath
|
|
passphraseStore map[string]string
|
|
mu sync.RWMutex
|
|
}
|
|
|
|
// NewAgent creates a new Agent instance
|
|
func NewAgent(conn *dbus.Conn, path dbus.ObjectPath) *Agent {
|
|
return &Agent{
|
|
conn: conn,
|
|
path: path,
|
|
passphraseStore: make(map[string]string),
|
|
}
|
|
}
|
|
|
|
// SetPassphrase stores a passphrase for a given network SSID
|
|
func (a *Agent) SetPassphrase(ssid, passphrase string) {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
a.passphraseStore[ssid] = passphrase
|
|
}
|
|
|
|
// ClearPassphrase removes the stored passphrase for a network
|
|
func (a *Agent) ClearPassphrase(ssid string) {
|
|
a.mu.Lock()
|
|
defer a.mu.Unlock()
|
|
delete(a.passphraseStore, ssid)
|
|
}
|
|
|
|
// Export registers the agent object on D-Bus
|
|
func (a *Agent) Export() error {
|
|
err := a.conn.Export(a, a.path, AgentInterface)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to export agent: %v", err)
|
|
}
|
|
|
|
err = a.conn.Export(introspect.Introspectable(agentIntrospectXML), a.path, "org.freedesktop.DBus.Introspectable")
|
|
if err != nil {
|
|
a.conn.Export(nil, a.path, AgentInterface)
|
|
return fmt.Errorf("failed to export introspection: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Unexport unregisters the agent from D-Bus
|
|
func (a *Agent) Unexport() {
|
|
a.conn.Export(nil, a.path, AgentInterface)
|
|
a.conn.Export(nil, a.path, "org.freedesktop.DBus.Introspectable")
|
|
}
|
|
|
|
// getNetworkSSID queries the network object to get its SSID (Name property)
|
|
func (a *Agent) getNetworkSSID(networkPath dbus.ObjectPath) (string, error) {
|
|
obj := a.conn.Object(Service, networkPath)
|
|
variant, err := obj.GetProperty(NetworkInterface + ".Name")
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get network name: %v", err)
|
|
}
|
|
|
|
name, ok := variant.Value().(string)
|
|
if !ok {
|
|
return "", fmt.Errorf("network name is not a string")
|
|
}
|
|
|
|
return name, nil
|
|
}
|
|
|
|
// RequestPassphrase is called by iwd when connecting to PSK networks
|
|
func (a *Agent) RequestPassphrase(network dbus.ObjectPath) (string, *dbus.Error) {
|
|
fmt.Printf("[Agent] RequestPassphrase called for network: %s\n", network)
|
|
|
|
ssid, err := a.getNetworkSSID(network)
|
|
if err != nil {
|
|
fmt.Printf("[Agent] Failed to get SSID: %v\n", err)
|
|
return "", dbus.MakeFailedError(fmt.Errorf("failed to get network SSID: %v", err))
|
|
}
|
|
|
|
fmt.Printf("[Agent] Network SSID: %s\n", ssid)
|
|
|
|
a.mu.RLock()
|
|
passphrase, ok := a.passphraseStore[ssid]
|
|
a.mu.RUnlock()
|
|
|
|
if !ok {
|
|
fmt.Printf("[Agent] No passphrase stored for SSID: %s\n", ssid)
|
|
return "", dbus.MakeFailedError(fmt.Errorf("no passphrase stored for network '%s'", ssid))
|
|
}
|
|
|
|
fmt.Printf("[Agent] Returning passphrase for SSID: %s\n", ssid)
|
|
return passphrase, nil
|
|
}
|
|
|
|
// RequestPrivateKeyPassphrase is called for encrypted private keys
|
|
func (a *Agent) RequestPrivateKeyPassphrase(network dbus.ObjectPath) (string, *dbus.Error) {
|
|
// Not implemented for now
|
|
return "", dbus.MakeFailedError(fmt.Errorf("RequestPrivateKeyPassphrase not implemented"))
|
|
}
|
|
|
|
// RequestUserNameAndPassword is called for enterprise networks
|
|
func (a *Agent) RequestUserNameAndPassword(network dbus.ObjectPath) (string, string, *dbus.Error) {
|
|
// Not implemented for now
|
|
return "", "", dbus.MakeFailedError(fmt.Errorf("RequestUserNameAndPassword not implemented"))
|
|
}
|
|
|
|
// RequestUserPassword is called for enterprise networks with known username
|
|
func (a *Agent) RequestUserPassword(network dbus.ObjectPath, user string) (string, *dbus.Error) {
|
|
// Not implemented for now
|
|
return "", dbus.MakeFailedError(fmt.Errorf("RequestUserPassword not implemented"))
|
|
}
|
|
|
|
// Cancel is called when a request is canceled
|
|
func (a *Agent) Cancel(reason string) *dbus.Error {
|
|
// Nothing to do, just acknowledge
|
|
return nil
|
|
}
|
|
|
|
// Release is called when the agent is unregistered
|
|
func (a *Agent) Release() *dbus.Error {
|
|
// Cleanup if needed
|
|
a.mu.Lock()
|
|
a.passphraseStore = make(map[string]string)
|
|
a.mu.Unlock()
|
|
return nil
|
|
}
|