Exemple #1
0
func ParseSlurpOutputErrResponse(response string, stdout io.Writer, stderr io.Writer) (finished bool, exitCode int, err error) {
	doc, err := xmlpath.Parse(strings.NewReader(response))

	stdouts, _ := xpath(doc, "//rsp:Stream[@Name='stdout']")
	for _, node := range stdouts {
		content, _ := base64.StdEncoding.DecodeString(node.String())
		stdout.Write(content)
	}
	stderrs, _ := xpath(doc, "//rsp:Stream[@Name='stderr']")
	for _, node := range stderrs {
		content, _ := base64.StdEncoding.DecodeString(node.String())
		stderr.Write(content)
	}

	ended, _ := any(doc, "//*[@State='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done']")

	if ended {
		finished = ended
		if exitBool, _ := any(doc, "//rsp:ExitCode"); exitBool {
			exit, _ := first(doc, "//rsp:ExitCode")
			exitCode, _ = strconv.Atoi(exit)
		}
	} else {
		finished = false
	}

	return
}
Exemple #2
0
func Test_executing_a_regex_command(t *testing.T) {
	w := &wsman{}
	id := w.HandleCommand(MatchPattern(`echo .* >> C:\file.cmd`), func(out, err io.Writer) int {
		return 0
	})

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "", strings.NewReader(fmt.Sprintf(`
		<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
			<env:Header>
				<a:Action mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/shell/Command</a:Action>
			</env:Header>
			<env:Body>
				<rsp:CommandLine><rsp:Command>"echo %d >> C:\file.cmd"</rsp:Command></rsp:CommandLine>
			</env:Body>
		</env:Envelope>`, uuid.NewV4().String())))

	w.ServeHTTP(res, req)
	if res.Code != http.StatusOK {
		t.Errorf("Expected 200 OK but was %d.\n", res.Code)
	}

	env, err := xmlpath.Parse(res.Body)
	if err != nil {
		t.Error("Couldn't compile the SOAP response.")
	}

	xpath, _ := xmlpath.CompileWithNamespace(
		"//rsp:CommandId", soap.GetAllNamespaces())

	result, _ := xpath.String(env)
	if result != id {
		t.Errorf("Expected CommandId=%s but was \"%s\"", id, result)
	}
}
Exemple #3
0
func parseXPath(doc *dom.Document, request string) (*xmlpath.Node, *xmlpath.Path, error) {
	content := strings.NewReader(doc.String())
	node, err := xmlpath.Parse(content)
	if err != nil {
		return nil, nil, err
	}

	path, err := xmlpath.CompileWithNamespace(request, soap.GetAllNamespaces())
	if err != nil {
		return nil, nil, err
	}

	return node, path, nil
}
Exemple #4
0
func assertXPath(c *C, node *dom.Document, request string, expected string) {
	content := strings.NewReader(node.String())

	path, err := xmlpath.CompileWithNamespace(request, soap.GetAllNamespaces())
	if err != nil {
		c.Fatalf("Xpath %s gives error %s", request, err)
	}
	var root *xmlpath.Node
	root, err = xmlpath.Parse(content)
	if err != nil {
		c.Fatalf("Xpath %s gives error %s", request, err)
	}

	var e string
	var ok bool
	e, ok = path.String(root)
	c.Assert(ok, Equals, true)
	c.Assert(e, Equals, expected)
}
Exemple #5
0
func Test_creating_a_shell(t *testing.T) {
	w := &wsman{}

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "", strings.NewReader(`
		<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing">
			<env:Header>
				<a:Action mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/transfer/Create</a:Action>
			</env:Header>
			<env:Body>
				<rsp:Shell>
					<rsp:InputStream>stdin</rsp:InputStream>
					<rsp:OutputStreams>stdout stderr</rsp:OutputStreams>
				</rsp:Shell>
			</env:Body>
		</env:Envelope>`))

	w.ServeHTTP(res, req)
	if res.Code != http.StatusOK {
		t.Errorf("Expected 200 OK but was %d.\n", res.Code)
	}

	if contentType := res.HeaderMap.Get("Content-Type"); contentType != "application/soap+xml" {
		t.Errorf("Expected ContentType application/soap+xml was %s.\n", contentType)
	}

	env, err := xmlpath.Parse(res.Body)
	if err != nil {
		t.Error("Couldn't compile the SOAP response.")
	}

	xpath, _ := xmlpath.CompileWithNamespace(
		"//rsp:ShellId", soap.GetAllNamespaces())

	if _, found := xpath.String(env); !found {
		t.Error("Expected a Shell identifier.")
	}
}
Exemple #6
0
func Test_receiving_command_results(t *testing.T) {
	w := &wsman{}
	id := w.HandleCommand(MatchText("echo tacos"), func(out, err io.Writer) int {
		out.Write([]byte("tacos"))
		return 0
	})

	res := httptest.NewRecorder()
	req, _ := http.NewRequest("POST", "", strings.NewReader(fmt.Sprintf(`
		<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
			<env:Header>
				<a:Action mustUnderstand="true">http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive</a:Action>
			</env:Header>
			<env:Body>
				<rsp:Receive><rsp:DesiredStream CommandId="%s">stdout stderr</rsp:DesiredStream></rsp:Receive>
			</env:Body>
		</env:Envelope>`, id)))

	w.ServeHTTP(res, req)
	if res.Code != http.StatusOK {
		t.Errorf("Expected 200 OK but was %d.\n", res.Code)
	}

	env, err := xmlpath.Parse(res.Body)
	if err != nil {
		t.Error("Couldn't compile the SOAP response.")
	}

	xpath, _ := xmlpath.CompileWithNamespace("//rsp:ReceiveResponse", soap.GetAllNamespaces())
	iter := xpath.Iter(env)
	if !iter.Next() {
		t.Error("Expected a ReceiveResponse element.")
	}

	xresp := iter.Node()
	xpath, _ = xmlpath.CompileWithNamespace(
		fmt.Sprintf("rsp:Stream[@CommandId='%s']", id), soap.GetAllNamespaces())
	iter = xpath.Iter(xresp)

	if !iter.Next() || !nodeHasAttribute(iter.Node(), "Name", "stdout") || iter.Node().String() != "dGFjb3M=" {
		t.Error("Expected an stdout Stream with the text \"dGFjb3M=\".")
	}

	if !iter.Next() || !nodeHasAttribute(iter.Node(), "Name", "stdout") || !nodeHasAttribute(iter.Node(), "End", "true") {
		t.Error("Expected an stdout Stream with an \"End\" attribute.")
	}

	if !iter.Next() || !nodeHasAttribute(iter.Node(), "Name", "stderr") || !nodeHasAttribute(iter.Node(), "End", "true") {
		t.Error("Expected an stderr Stream with an \"End\" attribute.")
	}

	xpath, _ = xmlpath.CompileWithNamespace(
		"//rsp:CommandState[@State='http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done']",
		soap.GetAllNamespaces())

	if _, found := xpath.String(env); !found {
		t.Error("Expected CommandState=\"Done\"")
	}

	xpath, _ = xmlpath.CompileWithNamespace("//rsp:CommandState/rsp:ExitCode", soap.GetAllNamespaces())
	if code, _ := xpath.String(env); code != "0" {
		t.Errorf("Expected ExitCode=0 but found \"%s\"\n", code)
	}
}
Exemple #7
0
func ParseExecuteCommandResponse(response string) (commandId string, err error) {
	doc, err := xmlpath.Parse(strings.NewReader(response))

	commandId, err = first(doc, "//rsp:CommandId")
	return
}
Exemple #8
0
func ParseOpenShellResponse(response string) (shellId string, err error) {
	doc, err := xmlpath.Parse(strings.NewReader(response))

	shellId, err = first(doc, "//w:Selector[@Name='ShellId']")
	return
}
Exemple #9
0
func (w *wsman) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	rw.Header().Add("Content-Type", "application/soap+xml")

	defer r.Body.Close()
	env, err := xmlpath.Parse(r.Body)

	if err != nil {
		return
	}

	action := readAction(env)
	switch {
	case strings.HasSuffix(action, "transfer/Create"):
		// create a new shell

		rw.Write([]byte(`
			<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
				<rsp:ShellId>123</rsp:ShellId>
			</env:Envelope>`))

	case strings.HasSuffix(action, "shell/Command"):
		// execute on behalf of the client
		text := readCommand(env)
		cmd := w.CommandByText(text)

		if cmd == nil {
			fmt.Printf("I don't know this command: Command=%s\n", text)
			rw.WriteHeader(http.StatusInternalServerError)
			return
		}

		rw.Write([]byte(fmt.Sprintf(`
			<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
				<rsp:CommandId>%s</rsp:CommandId>
			</env:Envelope>`, cmd.id)))

	case strings.HasSuffix(action, "shell/Receive"):
		// client ready to receive the results

		id := readCommandIDFromDesiredStream(env)
		cmd := w.CommandByID(id)

		if cmd == nil {
			fmt.Printf("I don't know this command: CommandId=%s\n", id)
			rw.WriteHeader(http.StatusInternalServerError)
			return
		}

		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)
		result := cmd.handler(stdout, stderr)
		content := base64.StdEncoding.EncodeToString(stdout.Bytes())

		rw.Write([]byte(fmt.Sprintf(`
			<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:rsp="http://schemas.microsoft.com/wbem/wsman/1/windows/shell">
				<rsp:ReceiveResponse>
					<rsp:Stream Name="stdout" CommandId="%s">%s</rsp:Stream>
					<rsp:Stream Name="stdout" CommandId="%s" End="true"></rsp:Stream>
					<rsp:Stream Name="stderr" CommandId="%s" End="true"></rsp:Stream>
					<rsp:CommandState State="http://schemas.microsoft.com/wbem/wsman/1/windows/shell/CommandState/Done">
						<rsp:ExitCode>%d</rsp:ExitCode>
					</rsp:CommandState>
				</rsp:ReceiveResponse>
			</env:Envelope>`, id, content, id, id, result)))

	case strings.HasSuffix(action, "shell/Signal"):
		// end of the shell command
		rw.WriteHeader(http.StatusOK)
	case strings.HasSuffix(action, "transfer/Delete"):
		// end of the session
		rw.WriteHeader(http.StatusOK)
	default:
		fmt.Printf("I don't know this action: %s\n", action)
		rw.WriteHeader(http.StatusInternalServerError)
	}
}