package main import ( "bufio" "encoding/xml" "fmt" "net/http" "os" "strings" ) // The XML response returned by the WatchGuard server type Resp struct { Action string `xml:"action"` LogonStatus int `xml:"logon_status"` LogonId int `xml:"logon_id"` Error string `xml:"errStr"` Challenge string `xml:"chaStr"` } func main() { args := os.Args[1:] if len(args) != 3 { fmt.Fprintf(os.Stderr, "Usage: watchblob \n") os.Exit(1) } host := args[0] username := args[1] password := args[2] challenge, err := triggerChallengeResponse(&host, &username, &password) if err != nil || challenge.LogonStatus != 4 { fmt.Fprintln(os.Stderr, "Did not receive challenge from server") fmt.Fprintf(os.Stderr, "Response: %v\nError: %v\n", challenge, err) os.Exit(1) } token := getToken(&challenge) err = logon(&host, &challenge, &token) if err != nil { fmt.Fprintf(os.Stderr, "Logon failed: %v\n", err) os.Exit(1) } fmt.Println("Login succeeded, you may now (quickly) authenticate OpenVPN with %s as your password", token) } func triggerChallengeResponse(host *string, username *string, password *string) (r Resp, err error) { return request(templateUrl(host, templateChallengeTriggerUri(username, password))) } func getToken(challenge *Resp) string { fmt.Println(challenge.Challenge) reader := bufio.NewReader(os.Stdin) token, _ := reader.ReadString('\n') return strings.TrimSpace(token) } func logon(host *string, challenge *Resp, token *string) (err error) { resp, err := request(templateUrl(host, templateResponseUri(challenge.LogonId, token))) if err != nil { return } if resp.LogonStatus != 1 { err = fmt.Errorf("Challenge/response authentication failed: %v", resp) } return } func request(url string) (r Resp, err error) { fmt.Println(url) resp, err := http.Get(url) if err != nil { return } defer resp.Body.Close() decoder := xml.NewDecoder(resp.Body) err = decoder.Decode(&r) return }