Skip to content
This repository was archived by the owner on Sep 21, 2020. It is now read-only.

Commit 68f8e70

Browse files
author
PinkLolicorn
committed
Allow to specify user to run screen on
1 parent ed5e91c commit 68f8e70

5 files changed

Lines changed: 84 additions & 29 deletions

File tree

command.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package main
2+
3+
import (
4+
"github.com/pkg/errors"
5+
"os/exec"
6+
"os/user"
7+
"strconv"
8+
"syscall"
9+
)
10+
11+
type UserInfo struct {
12+
name string
13+
gid uint32
14+
uid uint32
15+
}
16+
17+
func getUserInfoByName(userName string) (UserInfo, error) {
18+
19+
screenUser, err := user.Lookup(userName)
20+
if err != nil {
21+
return UserInfo{}, err
22+
}
23+
24+
gid64, _ := strconv.ParseUint(screenUser.Gid, 10, 32)
25+
gid := uint32(gid64)
26+
27+
uid64, _ := strconv.ParseUint(screenUser.Uid, 10, 32)
28+
uid := uint32(uid64)
29+
30+
return UserInfo{userName, gid, uid}, nil
31+
}
32+
33+
func executeCommand(userInfo UserInfo, args ...string) (string, error) {
34+
35+
baseCmd := args[0]
36+
cmdArgs := args[1:]
37+
38+
cmd := exec.Command(baseCmd, cmdArgs...)
39+
currentUser, _ := user.Current()
40+
root := currentUser.Gid == "0"
41+
42+
if userInfo.name != currentUser.Username && !root {
43+
return "", errors.New("Screen daemon requires root privileges to switch between users")
44+
}
45+
46+
if root {
47+
cmd.SysProcAttr = &syscall.SysProcAttr{}
48+
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: userInfo.uid, Gid: userInfo.gid}
49+
}
50+
51+
out, err := cmd.Output()
52+
if err != nil {
53+
return string(out), err
54+
}
55+
56+
return string(out), nil
57+
}

daemon.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
type ScreenInfo struct {
2626
Name string `ini:"name"`
27+
User string `ini:"user"`
2728
}
2829

2930
type ExecutionInfo struct {

daemons/example.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[Screen]
22
name = Example Daemon
3+
user = example
34

45
[Execution]
56
command = bash

main.go

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,11 @@ package main
2020

2121
import (
2222
"log"
23-
"os/exec"
2423
"path/filepath"
2524
"strconv"
2625
"time"
2726
)
2827

29-
func executeCommand(args ...string) (string, error) {
30-
31-
baseCmd := args[0]
32-
cmdArgs := args[1:]
33-
34-
cmd := exec.Command(baseCmd, cmdArgs...)
35-
out, err := cmd.Output()
36-
if err != nil {
37-
return string(out), err
38-
}
39-
40-
return string(out), nil
41-
}
42-
4328
func main() {
4429

4530
files, err := filepath.Glob("daemons/*.ini")
@@ -71,20 +56,21 @@ func main() {
7156

7257
command := daemon.Command
7358
name := daemon.Name
59+
user := daemon.User
7460

75-
screen, err := runScreen(name, command)
61+
screen, err := runScreen(user, name, command)
7662
if err != nil {
7763
if err.Error() == "SCREEN_ALREADY_EXISTS" {
7864
if firstRun {
79-
log.Print("(", name, ") WARNING: skipped, screen already exists")
65+
log.Print("(", name, " on ", user, ") WARNING: skipped, screen already exists")
8066
}
8167
} else {
82-
log.Fatal("(", name, ") FAILED: ", command, " [", err, "]")
68+
log.Fatal("(", name, " on ", user, ") FAILED: ", command, " [", err, "]")
8369
}
8470
continue
8571
}
8672

87-
log.Print("(" + strconv.Itoa(screen.id) + ", " + screen.name + ") STARTED: " + command)
73+
log.Print("("+strconv.Itoa(screen.id)+", "+screen.name, " on ", user, ") STARTED: "+command)
8874
}
8975

9076
firstRun = false

screen.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ type Screen struct {
2929
name string
3030
}
3131

32-
func runScreen(screenName string, command string) (Screen, error) {
32+
func runScreen(userName string, screenName string, command string) (Screen, error) {
3333

34-
exists, err := doesScreenExists(screenName)
34+
exists, err := doesScreenExists(userName, screenName)
3535
if err != nil {
3636
return Screen{}, err
3737
}
@@ -43,15 +43,20 @@ func runScreen(screenName string, command string) (Screen, error) {
4343
args := []string{"screen", "-dmS", screenName}
4444
args = append(args, strings.Split(command, " ")...)
4545

46-
_, err = executeCommand(args...)
46+
userInfo, err := getUserInfoByName(userName)
47+
if err != nil {
48+
return Screen{}, err
49+
}
50+
51+
_, err = executeCommand(userInfo, args...)
4752
if err != nil {
4853
if err.Error() == "exit status 1" {
4954
return Screen{}, errors.New("exit status 1: check command")
5055
}
5156
return Screen{}, err
5257
}
5358

54-
screen, err := getScreenByName(screenName)
59+
screen, err := getScreenByName(userName, screenName)
5560
if err != nil {
5661
if err.Error() == "SCREEN_NOT_FOUND" {
5762
return Screen{}, errors.New("Screen " + screenName + " not present after creation")
@@ -62,9 +67,14 @@ func runScreen(screenName string, command string) (Screen, error) {
6267
return screen, nil
6368
}
6469

65-
func getRunningScreens() ([]Screen, error) {
70+
func getRunningScreens(userName string) ([]Screen, error) {
71+
72+
userInfo, err := getUserInfoByName(userName)
73+
if err != nil {
74+
return []Screen{}, err
75+
}
6676

67-
output, err := executeCommand("screen", "-ls")
77+
output, err := executeCommand(userInfo, "screen", "-ls")
6878
if err != nil {
6979
if !strings.HasPrefix(output, "No Sockets found in") {
7080
return []Screen{}, err
@@ -96,9 +106,9 @@ func getRunningScreens() ([]Screen, error) {
96106
return screens, nil
97107
}
98108

99-
func doesScreenExists(screenName string) (bool, error) {
109+
func doesScreenExists(userName string, screenName string) (bool, error) {
100110

101-
_, err := getScreenByName(screenName)
111+
_, err := getScreenByName(userName, screenName)
102112
if err != nil {
103113
if err.Error() == "SCREEN_NOT_FOUND" {
104114
return false, nil
@@ -109,9 +119,9 @@ func doesScreenExists(screenName string) (bool, error) {
109119
return true, nil
110120
}
111121

112-
func getScreenByName(screenName string) (Screen, error) {
122+
func getScreenByName(userName string, screenName string) (Screen, error) {
113123

114-
screens, err := getRunningScreens()
124+
screens, err := getRunningScreens(userName)
115125
if err != nil {
116126
return Screen{}, err
117127
}

0 commit comments

Comments
 (0)