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
}
}
|