File: utils.go

package info (click to toggle)
ssh-tpm-agent 0.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 420 kB
  • sloc: makefile: 72
file content (158 lines) | stat: -rw-r--r-- 3,698 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package utils

import (
	"errors"
	"fmt"
	"html/template"
	"io/fs"
	"os"
	"path"

	"github.com/foxboron/ssh-tpm-agent/contrib"
	"github.com/google/go-tpm/tpm2"
)

func SSHDir() string {
	dirname, err := os.UserHomeDir()
	if err != nil {
		panic("$HOME is not defined")
	}

	return path.Join(dirname, ".ssh")
}

func FileExists(s string) bool {
	_, err := os.Stat(s)

	return !errors.Is(err, fs.ErrNotExist)
}

// This is the sort of things I swore I'd never write.
// but here we are.
func fmtSystemdInstallPath() string {
	DESTDIR := ""
	if val, ok := os.LookupEnv("DESTDIR"); ok {
		DESTDIR = val
	}

	PREFIX := "/usr/"
	if val, ok := os.LookupEnv("PREFIX"); ok {
		PREFIX = val
	}

	return path.Join(DESTDIR, PREFIX, "lib/systemd")
}

// Installs user units to the target system.
// It will either place the files under $HOME/.config/systemd/user or if global
// is supplied (through --install-system) into system user directories.
//
// Passing the env TEMPLATE_BINARY will use /usr/bin/ssh-tpm-agent for the
// binary in the service
func InstallUserUnits(global bool) error {
	if global || os.Getuid() == 0 { // If ran as root, install global system units
		return installUnits(path.Join(fmtSystemdInstallPath(), "/user/"), contrib.EmbeddedUserServices())
	}

	dirname, err := os.UserHomeDir()
	if err != nil {
		return err
	}

	return installUnits(path.Join(dirname, ".config/systemd/user"), contrib.EmbeddedUserServices())
}

func InstallHostkeyUnits() error {
	return installUnits(path.Join(fmtSystemdInstallPath(), "/system/"), contrib.EmbeddedSystemServices())
}

func installUnits(installPath string, files map[string][]byte) (err error) {
	execPath := os.Getenv("TEMPLATE_BINARY")
	if execPath == "" {
		execPath, err = os.Executable()
		if err != nil {
			return err
		}
	}

	if !FileExists(installPath) {
		if err := os.MkdirAll(installPath, 0o750); err != nil {
			return fmt.Errorf("creating service installation directory: %w", err)
		}
	}

	for name := range files {
		servicePath := path.Join(installPath, name)
		if FileExists(servicePath) {
			fmt.Printf("%s exists. Not installing units.\n", servicePath)
			return nil
		}
	}

	for name, data := range files {
		servicePath := path.Join(installPath, name)

		f, err := os.OpenFile(servicePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
		if err != nil {
			return err
		}
		defer f.Close()

		t := template.Must(template.New("service").Parse(string(data)))
		if err = t.Execute(f, &map[string]string{
			"GoBinary": execPath,
		}); err != nil {
			return err
		}

		fmt.Printf("Installed %s\n", servicePath)
	}

	return nil
}

func InstallSshdConf() error {
	// If ran as root, install sshd config
	if uid := os.Getuid(); uid != 0 {
		return fmt.Errorf("needs to be run as root")
	}

	sshdConfInstallPath := "/etc/ssh/sshd_config.d/"

	if !FileExists(sshdConfInstallPath) {
		return nil
	}

	files := contrib.EmbeddedSshdConfig()
	for name := range files {
		ff := path.Join(sshdConfInstallPath, name)
		if FileExists(ff) {
			fmt.Printf("%s exists. Not installing sshd config.\n", ff)
			return nil
		}
	}
	for name, data := range files {
		ff := path.Join(sshdConfInstallPath, name)
		if err := os.WriteFile(ff, data, 0o644); err != nil {
			return fmt.Errorf("failed writing sshd conf: %v", err)
		}
		fmt.Printf("Installed %s\n", ff)
	}
	fmt.Println("Restart sshd: systemd restart sshd")
	return nil
}

func GetParentHandle(ph string) (tpm2.TPMHandle, error) {
	switch ph {
	case "endoresement", "e":
		return tpm2.TPMRHEndorsement, nil
	case "null", "n":
		return tpm2.TPMRHNull, nil
	case "plattform", "p":
		return tpm2.TPMRHPlatform, nil
	case "owner", "o":
		fallthrough
	default:
		return tpm2.TPMRHOwner, nil
	}
}