145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
package dbus
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.ophivana.moe/cat/fortify/helper"
|
|
"git.ophivana.moe/cat/fortify/helper/bwrap"
|
|
"git.ophivana.moe/cat/fortify/ldd"
|
|
)
|
|
|
|
// Start launches the D-Bus proxy and sets up the Wait method.
|
|
// ready should be buffered and must only be received from once.
|
|
func (p *Proxy) Start(ready chan error, output io.Writer, sandbox bool) error {
|
|
p.lock.Lock()
|
|
defer p.lock.Unlock()
|
|
|
|
if p.seal == nil {
|
|
return errors.New("proxy not sealed")
|
|
}
|
|
|
|
var (
|
|
h helper.Helper
|
|
cmd *exec.Cmd
|
|
|
|
argF = func(argsFD, statFD int) []string {
|
|
if statFD == -1 {
|
|
return []string{"--args=" + strconv.Itoa(argsFD)}
|
|
} else {
|
|
return []string{"--args=" + strconv.Itoa(argsFD), "--fd=" + strconv.Itoa(statFD)}
|
|
}
|
|
}
|
|
)
|
|
|
|
if !sandbox {
|
|
h = helper.New(p.seal, p.name, argF)
|
|
cmd = h.Unwrap()
|
|
// xdg-dbus-proxy does not need to inherit the environment
|
|
cmd.Env = []string{}
|
|
} else {
|
|
// look up absolute path if name is just a file name
|
|
toolPath := p.name
|
|
if filepath.Base(p.name) == p.name {
|
|
if s, err := exec.LookPath(p.name); err == nil {
|
|
toolPath = s
|
|
}
|
|
}
|
|
|
|
// resolve libraries by parsing ldd output
|
|
var proxyDeps []*ldd.Entry
|
|
if path.IsAbs(toolPath) {
|
|
if l, err := ldd.Exec(toolPath); err != nil {
|
|
return err
|
|
} else {
|
|
proxyDeps = l
|
|
}
|
|
}
|
|
|
|
bc := &bwrap.Config{
|
|
Unshare: nil,
|
|
Hostname: "fortify-dbus",
|
|
Chdir: "/",
|
|
Clearenv: true,
|
|
NewSession: true,
|
|
DieWithParent: true,
|
|
}
|
|
|
|
// resolve proxy socket directories
|
|
bindTarget := make(map[string]struct{}, 2)
|
|
for _, ps := range []string{p.session[1], p.system[1]} {
|
|
if pd := path.Dir(ps); len(pd) > 0 {
|
|
if pd[0] == '/' {
|
|
bindTarget[pd] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
bindTargetDedup := make([][2]string, 0, len(bindTarget))
|
|
for k := range bindTarget {
|
|
bindTargetDedup = append(bindTargetDedup, [2]string{k, k})
|
|
}
|
|
bc.Bind = append(bc.Bind, bindTargetDedup...)
|
|
|
|
roBindTarget := make(map[string]struct{}, 2+1+len(proxyDeps))
|
|
|
|
// xdb-dbus-proxy bin and dependencies
|
|
roBindTarget[path.Dir(toolPath)] = struct{}{}
|
|
for _, ent := range proxyDeps {
|
|
if path.IsAbs(ent.Path) {
|
|
roBindTarget[path.Dir(ent.Path)] = struct{}{}
|
|
}
|
|
}
|
|
|
|
// resolve upstream bus directories
|
|
for _, as := range []string{p.session[0], p.system[0]} {
|
|
if len(as) > 0 && strings.HasPrefix(as, "unix:path=/") {
|
|
// leave / intact
|
|
roBindTarget[path.Dir(as[10:])] = struct{}{}
|
|
}
|
|
}
|
|
|
|
roBindTargetDedup := make([][2]string, 0, len(roBindTarget))
|
|
for k := range roBindTarget {
|
|
roBindTargetDedup = append(roBindTargetDedup, [2]string{k, k})
|
|
}
|
|
bc.ROBind = append(bc.ROBind, roBindTargetDedup...)
|
|
|
|
h = helper.MustNewBwrap(bc, p.seal, toolPath, argF)
|
|
cmd = h.Unwrap()
|
|
p.bwrap = bc
|
|
}
|
|
|
|
if output != nil {
|
|
cmd.Stdout = output
|
|
cmd.Stderr = output
|
|
}
|
|
if err := h.StartNotify(ready); err != nil {
|
|
return err
|
|
}
|
|
|
|
p.helper = h
|
|
return nil
|
|
}
|
|
|
|
// Wait waits for xdg-dbus-proxy to exit or fault.
|
|
func (p *Proxy) Wait() error {
|
|
p.lock.RLock()
|
|
defer p.lock.RUnlock()
|
|
|
|
if p.helper == nil {
|
|
return errors.New("proxy not started")
|
|
}
|
|
|
|
return p.helper.Wait()
|
|
}
|
|
|
|
// Close closes the status file descriptor passed to xdg-dbus-proxy, causing it to stop.
|
|
func (p *Proxy) Close() error {
|
|
return p.helper.Close()
|
|
}
|