Reputation: 11
I need to run a session as user2 from an already running session of user1 on a virtual display and I need to keep the integrity level low. Here is my implementation of the Go code to start the session:
type LaunchService struct {
displayNumberID string
customEnv []string
displayNumber int
processes map[string]int
ConnStatus models.Status
log *zerolog.Logger
sListener *SocketListener
execCommand func(name string, arg ...string) *exec.Cmd
}
func NewLaunchService(zlog *zerolog.Logger, sList *SocketListener) *LaunchService {
env := os.Environ()
dispNumber := 99
dispID := fmt.Sprintf(":%d", dispNumber)
env = append(env, fmt.Sprintf(`DISPLAY=%s`, dispID))
lService := &LaunchService{
customEnv: env,
log: zlog,
displayNumber: dispNumber,
displayNumberID: dispID,
sListener: sList,
ConnStatus: -1,
processes: make(map[string]int),
execCommand: exec.Command,
}
return lService
}
func (ls *LaunchService) StartDesktopSession(authData models.AuthData) error {
if err := ls.TerminateAllProcesses(); err != nil {
return err
}
group, _ := errgroup.WithContext(context.Background())
group.Go(func() error {
if err := ls.initEnvironment(authData.Username); err != nil {
return err
}
return nil
})
ls.log.Debug().Msg("Starting a graphical session")
group.Go(func() error {
if err := ls.startXVFB(authData); err != nil {
ls.log.Error().Err(err).Msg("Error when start xvfb-run")
return err
}
return nil
})
time.Sleep(time.Second)
group.Go(func() error {
if err := ls.startDesktop(authData.Username, authData.Desktop); err != nil {
return err
}
return nil
})
time.Sleep(time.Second)
group.Go(func() error {
if err := ls.startGlint(authData.Username); err != nil {
return err
}
return nil
})
time.Sleep(time.Second)
group.Go(func() error {
if err := ls.startPulseaudio(authData.Username); err != nil {
return err
}
return nil
})
time.Sleep(time.Second)
if err := group.Wait(); err != nil {
return err
}
return nil
}
func (ls *LaunchService) initEnvironment(usrname string) error {
ls.log.Debug().Msg("start audio")
cmd := ls.execCommand("sudo", "usermod", "-aG", "audio", usrname)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
ls.log.Error().Err(err).Msg("Error when authorizing the use of the sound card")
return fmt.Errorf(errText.AuthSoundCardErr, err)
}
cmd = ls.execCommand("sudo", "mkhomedir_helper", usrname)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
ls.log.Error().Err(err).Msg("error when creating a home directory for a user " + usrname)
return fmt.Errorf(errText.MkHomeDirErr, usrname, err)
}
ls.log.Debug().Msg("starting audio finished")
return nil
}
func (ls *LaunchService) startXVFB(auth models.AuthData) error {
if err := ls.deleteTempFiles(); err != nil {
return err
}
ls.log.Debug().Msg("start XVFB")
cmd := ls.execCommand("sudo", "-u", auth.Username, "Xvfb", ls.displayNumberID,
"-screen", "0", fmt.Sprintf("%dx%dx%d", auth.Width, auth.Height, auth.Depth))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
ls.log.Error().Err(err).Msg("Error when authorizing the use of the sound card")
return fmt.Errorf(errText.XVFBStartErr, err)
}
time.Sleep(time.Second)
if err := ls.writeProcess("Xvfb"); err != nil {
return err
}
ls.log.Debug().Msg("starting XVFB finished")
return nil
}
func (ls *LaunchService) startDesktop(usrname string, desktop string) error {
ls.log.Debug().Msg("start desktop")
cmd := ls.execCommand("sudo", "-u", usrname, "fly-wm", "--noparse")
ls.log.Debug().Any("cmd args", cmd.Args).Msg("Check startDesktop comm args")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Env = ls.customEnv
if err := cmd.Start(); err != nil {
ls.log.Error().Err(err).Msg("Error when starting desktop")
return fmt.Errorf(errText.XFCEStartErr, err)
}
time.Sleep(time.Second)
if err := ls.writeProcess("fly-wm"); err != nil {
return err
}
ls.log.Debug().Str("desktop environment", desktop).Msg("starting desktop finished")
return nil
}
func (ls *LaunchService) startPulseaudio(usrname string) error {
ls.log.Debug().Msg("start pulseaudio")
cmd := ls.execCommand("sudo", "-u", usrname, "pulseaudio")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
ls.log.Error().Err(err).Msg("Error when starting pulseaudio")
return fmt.Errorf(errText.PulseAudioStartErr, err)
}
ls.log.Debug().Int("pulseaudio pid", cmd.Process.Pid).Msg("Process id pulseaudio")
ls.processes["pulseaudio"] = cmd.Process.Pid
ls.log.Debug().Msg("starting pulseaudio finished")
return nil
}
func (ls *LaunchService) deleteTempFiles() error {
xUnix := fmt.Sprintf("/tmp/.X11-unix/X%d", ls.displayNumber)
xLock := fmt.Sprintf("/tmp/.X%d-lock", ls.displayNumber)
xUnixExist, err := isFileExist(xUnix)
if err != nil {
return err
}
xLockExist, err := isFileExist(xLock)
if err != nil {
return err
}
if xUnixExist {
if err = os.Remove(xUnix); err != nil {
ls.log.Error().Err(err).Msg("Error when deleting " + xUnix)
return fmt.Errorf(errText.TemtDeleteErr, xUnix, err)
}
}
if xLockExist {
if err = os.Remove(xLock); err != nil {
ls.log.Error().Err(err).Msg("Error when deleting " + xLock)
return fmt.Errorf(errText.TemtDeleteErr, xLock, err)
}
}
return nil
}
Before running Authenticate the user with the following code:
func pamAuth(usrName, passwd string) error {
if err := clearFaillog(usrName); err != nil {
return err
}
transaction, err := pam.StartFunc("login", usrName, func(style pam.Style, msg string) (string, error) {
if style == pam.PromptEchoOff {
return passwd, nil
}
return "", fmt.Errorf(errTexts.PAMPromitErr, msg)
})
if err != nil {
return err
}
if err = transaction.Authenticate(0); err != nil {
return fmt.Errorf(errTexts.PAMAuthErr, err)
}
return nil
}
When you run this code, the session starts, but the integrity level check (pdp-id command) shows a high integrity level. Most likely, since the code is run under sudo as user1 (the code is run as a systemd service) integrity is inherited.
Tried limiting user2's max integrity to low, but the integrity level is still high when the session starts. I tried to start fly-dm and log in manually, but in this case just a black screen.
I also noticed the following warnings in the logs, but I couldn't deal with them:
** (process:24121): WARNING **: 17:15:57.307: Unable to register authentication agent:
GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: User of caller and user of subject differs.
"Cannot register authentication agent:
GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: User of caller and user of subject differs."
Authentication agent result: false
Couldn't register listener!
QDBusArgument: read from a write-only object
QDBusArgument: read from a write-only object
QDBusArgument: read from a write-only object
fly-wm [14:15:57] err: IceProcessMessagesIOError, state=0: client
'1c2737472000172234895700000241030005' '(null)'
fly-wm [14:15:57] err: ICE Connection closed due to
IceProcessMessagesIOError!
Upvotes: 1
Views: 65