127 lines
3.0 KiB
Go
127 lines
3.0 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
func usage() {
|
|
fmt.Printf("Usage: %s <keyserver> <image> <device>\n", os.Args[0])
|
|
fmt.Printf("Example: %s https://keyserver.example.com /path/to/image.img <device>\n", os.Args[0])
|
|
fmt.Printf("Example: %s https://keyserver.example.com /path/to/image.img /dev/mapper/crypt1\n", os.Args[0])
|
|
os.Exit(1)
|
|
}
|
|
|
|
func fileExists(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil
|
|
}
|
|
|
|
func deviceExists(device string) bool {
|
|
_, err := os.Stat("/dev/mapper/" + device)
|
|
return err == nil
|
|
}
|
|
|
|
func keyserverReachable(url string) bool {
|
|
resp, err := http.Head(url)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
resp.Body.Close()
|
|
return resp.StatusCode < 400
|
|
}
|
|
|
|
func getUUID() string {
|
|
// Get CPU model name
|
|
cpuinfo, _ := ioutil.ReadFile("/proc/cpuinfo")
|
|
var model string
|
|
for _, line := range strings.Split(string(cpuinfo), "\n") {
|
|
if strings.HasPrefix(line, "model name") {
|
|
model = line
|
|
break
|
|
}
|
|
}
|
|
// Get eth0 MAC address
|
|
iface, err := net.InterfaceByName("eth0")
|
|
mac := ""
|
|
if err == nil {
|
|
mac = iface.HardwareAddr.String()
|
|
}
|
|
// Get system UUID
|
|
out, _ := exec.Command("sudo", "dmidecode", "-s", "system-uuid").Output()
|
|
sysuuid := strings.TrimSpace(string(out))
|
|
uuid := model + mac + sysuuid
|
|
return uuid
|
|
}
|
|
|
|
func main() {
|
|
log.SetFlags(0)
|
|
if len(os.Args) != 4 {
|
|
usage()
|
|
}
|
|
keyserver := os.Args[1]
|
|
image := os.Args[2]
|
|
device := os.Args[3]
|
|
|
|
if !fileExists(image) {
|
|
log.Printf("open_volume: (%s) Image file not found", device)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if !keyserverReachable(keyserver) {
|
|
log.Printf("open_volume: (%s) Key server not reachable, exiting.", device)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if deviceExists(device) {
|
|
fmt.Printf("open_volume: (%s) Device already open, exiting.\n", device)
|
|
os.Exit(1)
|
|
}
|
|
|
|
uuid := getUUID()
|
|
h := md5.Sum([]byte(uuid))
|
|
keyid := hex.EncodeToString(h[:])
|
|
|
|
log.Printf("open_volume: (%s) Downloading key from key server,", device)
|
|
keyurl := fmt.Sprintf("%s/%s", keyserver, keyid)
|
|
resp, err := http.Get(keyurl)
|
|
if err != nil || resp.StatusCode != 200 {
|
|
log.Printf("open_volume: (%s) Failed to download key from key server", device)
|
|
os.Exit(1)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
tmpfile, err := ioutil.TempFile("", "keyfile")
|
|
if err != nil {
|
|
log.Printf("open_volume: (%s) Failed to create temp file", device)
|
|
os.Exit(1)
|
|
}
|
|
defer os.Remove(tmpfile.Name())
|
|
_, err = io.Copy(tmpfile, resp.Body)
|
|
tmpfile.Close()
|
|
if err != nil {
|
|
log.Printf("open_volume: (%s) Failed to save key file", device)
|
|
os.Exit(1)
|
|
}
|
|
|
|
log.Printf("open_volume:'%s' Key downloaded successfully, opening volume", device)
|
|
cmd := exec.Command("/usr/sbin/cryptsetup", "luksOpen", image, device, "-d", tmpfile.Name())
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
log.Printf("open_volume: (%s) Failed to open volume: %s", device, string(out))
|
|
os.Exit(1)
|
|
}
|
|
|
|
log.Printf("open_volume: (%s) Volume opened successfully, removing key file", device)
|
|
os.Exit(0)
|
|
}
|