diff --git a/config.json b/config.json new file mode 100644 index 0000000..be323ee --- /dev/null +++ b/config.json @@ -0,0 +1,18 @@ +// This is JSON. But with comments! They start with "//" (without the quotes) +{ + // The file(s) to watch. If no given file contains the + // signature and key in the keyfile, the screen is locked. + // You can use shell-replacemants like * and ? + "Lockfile": "/dev/sd??", + + // The file containing the key. + "Keyfile": "usblocker.key", + + // The location of the xlock binary. + "Xlock_path": "/usr/bin/xlock", + + // Exclude possible lockfiles, if they contain the wrong + // signature or no signature at all. + "Blacklist_devices": true +} + diff --git a/usblocker b/usblocker index 0655a60..5f14f11 100755 Binary files a/usblocker and b/usblocker differ diff --git a/usblocker.go b/usblocker.go index 66db611..eaa7cdf 100644 --- a/usblocker.go +++ b/usblocker.go @@ -1,15 +1,39 @@ package main import ( + //"code.google.com/p/gcfg" + "encoding/json" "fmt" + "io/ioutil" "log" "os" + "os/exec" "path/filepath" + "regexp" "strings" "time" ) +type Configuration struct { + Lockfile string + Keyfile string + Xlock_path string + Blacklist_devices bool +} + var VERSION = "v0.1.0" +var CONFIGFILE = "config.json" + +// Default configuration +var cfg = Configuration{ + Lockfile: "/dev/sd??", + Keyfile: "usblocker.key", + Xlock_path: "/bin/xlock", + Blacklist_devices: true, +} + +var FIRSTRUN = true +var cmd = exec.Command("") /* Shows the help message */ @@ -17,12 +41,12 @@ func ShowHelp() { fmt.Println("Watches a device and locks the screen if the device is missing.") fmt.Println() fmt.Println("Usage:") - fmt.Println(" usblocker run: Start USBLocker.") + fmt.Println(" usblocker start: Start USBLocker.") //fmt.Println(" usblocker daemon: Runs in background.") //fmt.Println(" usblocker create: Prepares a device for usage with USBLocker.") } -/* +/* Shows the message of the day */ func ShowMOTD() { fmt.Println("Welcome to USBLocker ", VERSION) @@ -42,74 +66,81 @@ func WatcherUnlocked(device string) { time.Sleep(time.Duration(1) * time.Second) } log.Println("Locked") - var args []string - args = append(args, "-nolock") // Fix for... something. First passed argument keeps beeing ignored, for whatever reason. - //args = append(args, "-info") - //args = append(args, "") - args = append(args, "-mode") - args = append(args, "blank") - //log.Println(args) - var attr os.ProcAttr - lpid, err := os.StartProcess("/usr/bin/xlock", args, &attr) + cmd = exec.Command("/usr/bin/xlock", "-mode", "blank") + err := cmd.Start() if err != nil { log.Fatal("Error: ", err) } - WatcherLocked(lpid) + + WatcherLocked() } /* Watcher for locked state / no device */ -func WatcherLocked(lpid *os.Process) { - var passphrase string // TEH KEY!!1! - var devices []string // list of devices - var lfile *os.File // device file - ldev := "" // device file name - version := "v0" // version string - - var passtest []byte - for i := 0; i < 1024; i++ { - passtest = append(passtest, 0) - } +func WatcherLocked() { + var passphrase string // the key + var passtest = make([]byte, 1024) // slice for testing the passphrase + var devices []string // list of devices + var devblacklist []string // blacklist of devices + var lfile *os.File // device file + ldev := "" // device file name + lfileversion := "v1" // version string // Set the passphrase passphrase = "wictQQT86qi7YhZP3wVIZek+x9X0ELJA5LN2amEdh54xXs0yGlGx2kRrfIXC+C3iIX9iYRMKrv0bFSyR29SVTVhl2Q0LFOvvAmawiRrJ9MLwyiBrTVfhsVLcZcKNI5Up6xjebezqyhTcZBzEuRYk4VueCXbjI0ISK0LQgMdKxiybQOt1+FLAmgtYj+izB4xvEd9A+wQOnb+wKqZ8TpWh8h/HVfQLgobXDND8I7SXYC1Qm5Kv4wUBWUDg3YOWwMLWfYvyCU4ZyKi5FG3GWvLvKKMxk7vHA/YDyz/eXo3x07zmqDqZHP19k9nGex6ubzmZOWLZz1zEwsdweXCqYps9waXwhJ/9zgrx735IRE3gPL/KYP/X5WTMBXMYFkCAzT6LHNO2gWzdHqdIjyBPBoOHDtVFhKp7prN6GCn/h4Bwr5VzxC+NrUQPG3AqdQdnNGf9zmUV7VE4ZtRdC5dA5I0rJkX9xIbps7IiF9TACIHwXWVEQ+VpQFXRT063DcMxzlmP0b55k4Y2YEZsFEIYO0/hNqMl5D/ETNriiKIpr296WfRqPC6RsGgodZ6TIA8/XqRWsmkCjBHHPSv7BfVDNUbH/hiINH+8U/YfUGfFOly301HXZlEpqLjCXdEw8kzNN06anFTd+6YsTOScGLeddi1urqUCQ9v5nM1iAoXj0djOUdbZks8RgXdf583hhwHWG/Ib5HLSr4ISMQxFhjWKcHvo4ffeYLiOP85ulNsL5ZbtOUL2MX/DuLE1mKopoj50Jjb0mV+QiXUkifjZgGuXyGuZYfNYtMSmkRGERkJfrLeQyd69o+CLG7sfywOgelFWHTwkeVQNbpjRPmTLdSsq0MuJeIlcIAEKECQgBkNMOE2WuHOC2jr8Ba018wESW/hXAairG7ft7Mmf+AMCdjamFhb56YFbE9LumQ8ILgK9q6FQ6OU39qP+wCivdtSEnDnip4EVw7yItj1/0GVs1QPr20gDHO0G2t90JPyApmqtfKq4CY/tKgDhAkBwNXyGEVCrsA==" for { var err error - devices, err = filepath.Glob("/dev/?d?1") + devices, err = filepath.Glob(cfg.Lockfile) if err != nil { - log.Fatal("Error while getting list of aviable devices (/dev/?d?1):", err) + log.Fatal("Error while getting list of aviable devices ", cfg.Lockfile, ":", err) + } + if len(devices) == 0 { + log.Fatal("Not found: ", cfg.Lockfile) } // Search lock device - for i := range devices { - log.Println("Checking", devices[i], "for usblocker data...") - lfile, err = os.Open(devices[i]) + for _, device := range devices { + log.Println("Checking", device, "for usblocker data...") + lfile, err = os.Open(device) if err != nil { log.Fatal("Error while opening the device file:", err) } // Check for magic string - magictest := []byte(" ") + magictest := make([]byte, 9) length, err := lfile.Read(magictest) if err != nil { log.Fatal("Error while reading the device file:", err) _ = lfile.Close() } if length == 9 && string(magictest) == "usblocker" { - ldev = devices[i] + ldev = device break + } else { + if cfg.Blacklist_devices && FIRSTRUN { + if len(devblacklist) == 0 { + devblacklist = append(devblacklist, device) + } else { + for _, v := range devblacklist { + if v != device { + devblacklist = append(devblacklist, device) + } + } + } + FIRSTRUN = false + } } } // Check lockdev version if ldev != "" { log.Println("Checking", ldev, "for right version...") - versiontest := []byte(" ") + versiontest := make([]byte, 7) length, err := lfile.Read(versiontest) if err != nil { log.Fatal("Error while reading the device file:", err) } - if length == 7 && strings.HasPrefix(string(versiontest), version) { + if length == 7 && strings.HasPrefix(string(versiontest), lfileversion) { log.Println("Checking passphrase...") length, err := lfile.Read(passtest) _ = lfile.Close() @@ -119,9 +150,9 @@ func WatcherLocked(lpid *os.Process) { if length == 1024 && string(passtest) == passphrase { // And finally: UNLOCK! log.Println("Unlocked") - if lpid != nil { - lpid.Kill() - _, _ = lpid.Wait() + if cmd.Process != nil { + cmd.Process.Kill() + _ = cmd.Wait() } WatcherUnlocked(ldev) } @@ -136,25 +167,47 @@ func WatcherLocked(lpid *os.Process) { */ func main() { // Determining what to do - if len(os.Args) == 1 { + if len(os.Args) < 2 { ShowHelp() return } switch os.Args[1] { - case "run": + case "start": //case "daemon": // log.Fatal("Not yet implemented. Probably won't be implemented anyway, go doesn't seem to support forking...") case "create": log.Fatal("Not yet implemented.") default: ShowHelp() + return } // Check for root if os.Getuid() != 0 { - log.Fatal("YU NO GOT ROOT??") + log.Fatal("Y U NO GOT ROOT??") + } + + // Get configuration from file config.json + b, err := ioutil.ReadFile(CONFIGFILE) + if err != nil { + log.Println("Cannot read configuration file:", err) + log.Println("Using default configuration") + } else { + re := regexp.MustCompile("(?m)^\\s*//.*$") + jdata := re.ReplaceAllString(string(b), "") + err = json.Unmarshal([]byte(jdata), &cfg) + if err != nil { + log.Fatal("Failed to get configuration from json:", err) + } + } + + // Check for xlock + _, err = os.Stat(cfg.Xlock_path) + if err != nil { + os.Stdout.Write([]byte("Is xlock installed and the right path set in config.json?\n")) + log.Fatal("Stat for ", cfg.Xlock_path, " failed:", err) } ShowMOTD() - WatcherLocked(nil) + WatcherLocked() }