Example #1
0
// parseSearchParameters transforms a query string into search parameters in the migdb format
func parseSearchParameters(qp url.Values) (p migdb.SearchParameters, filterFound bool, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("parseSearchParameters()-> %v", e)
		}
	}()
	p = migdb.NewSearchParameters()
	for queryParams, _ := range qp {
		switch queryParams {
		case "actionname":
			p.ActionName = qp["actionname"][0]
		case "actionid":
			p.ActionID = qp["actionid"][0]
		case "after":
			p.After, err = time.Parse(time.RFC3339, qp["after"][0])
			if err != nil {
				panic("after date not in RFC3339 format")
			}
		case "agentid":
			p.AgentID = qp["agentid"][0]
		case "agentname":
			p.AgentName = qp["agentname"][0]
		case "before":
			p.Before, err = time.Parse(time.RFC3339, qp["before"][0])
			if err != nil {
				panic("before date not in RFC3339 format")
			}
		case "commandid":
			p.CommandID = qp["commandid"][0]
		case "foundanything":
			if truere.MatchString(qp["foundanything"][0]) {
				p.FoundAnything = true
			} else if falsere.MatchString(qp["foundanything"][0]) {
				p.FoundAnything = false
			} else {
				panic("foundanything parameter must be true or false")
			}
			filterFound = true
		case "investigatorid":
			p.InvestigatorID = qp["investigatorid"][0]
		case "investigatorname":
			p.InvestigatorName = qp["investigatorname"][0]
		case "limit":
			p.Limit, err = strconv.ParseFloat(qp["limit"][0], 64)
			if err != nil {
				panic("invalid limit parameter")
			}
		case "report":
			switch qp["report"][0] {
			case "complianceitems":
				p.Report = qp["report"][0]
			case "geolocations":
				p.Report = qp["report"][0]
			default:
				panic("report not implemented")
			}
		case "status":
			p.Status = qp["status"][0]
		case "target":
			p.Target = qp["target"][0]
		case "threatfamily":
			p.ThreatFamily = qp["threatfamily"][0]
		case "type":
			p.Type = qp["type"][0]
		}
	}
	return
}
Example #2
0
// search runs searches
func search(respWriter http.ResponseWriter, request *http.Request) {
	var err error
	opid := mig.GenID()
	loc := fmt.Sprintf("http://%s:%d%s", ctx.Server.IP, ctx.Server.Port, request.URL.String())
	resource := cljs.New(loc)
	p := migdb.NewSearchParameters()
	defer func() {
		if e := recover(); e != nil {
			// on panic, log and return error to client, including the search parameters
			ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("%v", e)}.Err()
			resource.AddItem(cljs.Item{
				Href: loc,
				Data: []cljs.Data{{Name: "search parameters", Value: p}},
			})
			resource.SetError(cljs.Error{Code: fmt.Sprintf("%.0f", opid), Message: fmt.Sprintf("%v", e)})
			respond(500, resource, respWriter, request, opid)
		}
		ctx.Channels.Log <- mig.Log{OpID: opid, Desc: "leaving search()"}.Debug()
	}()
	doFoundAnythingFiltering := false
	timeLayout := time.RFC3339
	for queryParams, _ := range request.URL.Query() {
		switch queryParams {
		case "actionname":
			p.ActionName = request.URL.Query()["actionname"][0]
		case "actionid":
			p.ActionID = request.URL.Query()["actionid"][0]
		case "commandid":
			p.CommandID = request.URL.Query()["commandid"][0]
		case "after":
			p.After, err = time.Parse(timeLayout, request.URL.Query()["after"][0])
			if err != nil {
				panic("after date not in RFC3339 format")
			}
		case "agentid":
			p.AgentID = request.URL.Query()["agentid"][0]
		case "agentname":
			p.AgentName = request.URL.Query()["agentname"][0]
		case "before":
			p.Before, err = time.Parse(timeLayout, request.URL.Query()["before"][0])
			if err != nil {
				panic("before date not in RFC3339 format")
			}
		case "foundanything":
			switch request.URL.Query()["foundanything"][0] {
			case "true", "True", "TRUE":
				p.FoundAnything = true
			case "false", "False", "FALSE":
				p.FoundAnything = false
			default:
				panic("foundanything parameter must be true or false")
			}
			doFoundAnythingFiltering = true
		case "report":
			switch request.URL.Query()["report"][0] {
			case "complianceitems":
				p.Report = request.URL.Query()["report"][0]
			default:
				panic("report not implemented")
			}
		case "limit":
			p.Limit, err = strconv.ParseFloat(request.URL.Query()["limit"][0], 64)
			if err != nil {
				panic("invalid limit parameter")
			}
		case "status":
			p.Status = request.URL.Query()["status"][0]
		case "threatfamily":
			p.ThreatFamily = request.URL.Query()["threatfamily"][0]
		}
	}
	// run the search based on the type
	var results interface{}
	if _, ok := request.URL.Query()["type"]; ok {
		p.Type = request.URL.Query()["type"][0]
		switch p.Type {
		case "command":
			results, err = ctx.DB.SearchCommands(p)
		case "action":
			results, err = ctx.DB.SearchActions(p)
		case "agent":
			results, err = ctx.DB.SearchAgents(p)
		default:
			panic("search type is invalid")
		}
		if err != nil {
			panic(err)
		}
	} else {
		panic("search type is missing")
	}

	// if requested, filter results on the foundanything flag
	if doFoundAnythingFiltering && p.Type == "command" {
		results, err = filterResultsOnFoundAnythingFlag(results.([]mig.Command), p.FoundAnything)
		if err != nil {
			panic(err)
		}
	}

	// prepare the output in the requested format
	switch p.Report {
	case "complianceitems":
		if p.Type != "command" {
			panic("compliance items not available for this type")
		}
		beforeStr := url.QueryEscape(p.Before.Format(time.RFC3339Nano))
		afterStr := url.QueryEscape(p.After.Format(time.RFC3339Nano))
		items, err := commandsToComplianceItems(results.([]mig.Command))
		if err != nil {
			panic(err)
		}
		for i, item := range items {
			err = resource.AddItem(cljs.Item{
				Href: fmt.Sprintf("http://%s:%d%s/search?type=command?agentname=%s&commandid=%s&actionid=%s&threatfamily=compliance&report=complianceitems&after=%s&before=%s",
					ctx.Server.IP, ctx.Server.Port, ctx.Server.BaseRoute, item.Target,
					p.CommandID, p.ActionID, afterStr, beforeStr),
				Data: []cljs.Data{{Name: "compliance item", Value: item}},
			})
			if err != nil {
				panic(err)
			}
			if float64(i) > p.Limit {
				break
			}
		}
	default:
		switch p.Type {
		case "command":
			for _, r := range results.([]mig.Command) {
				err = resource.AddItem(cljs.Item{
					Href: fmt.Sprintf("http://%s:%d%s/command?commandid=%.0f",
						ctx.Server.IP, ctx.Server.Port, ctx.Server.BaseRoute, r.ID),
					Data: []cljs.Data{{Name: p.Type, Value: r}},
				})
				if err != nil {
					panic(err)
				}
			}
		case "action":
			for _, r := range results.([]mig.Action) {
				err = resource.AddItem(cljs.Item{
					Href: fmt.Sprintf("http://%s:%d%s/action?actionid=%.0f",
						ctx.Server.IP, ctx.Server.Port, ctx.Server.BaseRoute, r.ID),
					Data: []cljs.Data{{Name: p.Type, Value: r}},
				})
				if err != nil {
					panic(err)
				}
			}
		case "agent":
			for _, r := range results.([]mig.Agent) {
				err = resource.AddItem(cljs.Item{
					Href: fmt.Sprintf("http://%s:%d%s/agent?agentid=%.0f",
						ctx.Server.IP, ctx.Server.Port, ctx.Server.BaseRoute, r.ID),
					Data: []cljs.Data{{Name: p.Type, Value: r}},
				})
				if err != nil {
					panic(err)
				}
			}
		}
	}
	// add search parameters at the end of the response
	err = resource.AddItem(cljs.Item{
		Href: loc,
		Data: []cljs.Data{{Name: "search parameters", Value: p}},
	})
	if err != nil {
		panic(err)
	}
	respond(200, resource, respWriter, request, opid)
}