Beispiel #1
0
// expireCommands loads commands in the inflight directory
// and terminate the expired ones
func expireCommands(ctx Context) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("expireCommands() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: "leaving expireCommands()"}.Debug()
	}()
	dir, err := os.Open(ctx.Directories.Command.InFlight)
	dirContent, err := dir.Readdir(-1)
	if err != nil {
		panic(err)
	}
	// loop over the content of the directory
	for _, DirEntry := range dirContent {
		if !DirEntry.Mode().IsRegular() {
			// ignore non file
			continue
		}
		filename := ctx.Directories.Command.InFlight + "/" + DirEntry.Name()
		_, err = os.Stat(filename)
		if err != nil {
			// file is already gone, probably consumed by a concurrent returning command
			// ignore and continue
			continue
		}
		err := waitForFileOrDelete(filename, 3)
		if err != nil {
			ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("error while reading '%s': %v", filename, err)}.Err()
			continue
		}
		cmd, err := mig.CmdFromFile(filename)
		if err != nil {
			// failing to load this file, log and skip it
			ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: fmt.Sprintf("failed to load inflight command file %s", filename)}.Err()
			continue
		}

		if time.Now().After(cmd.Action.ExpireAfter) {
			desc := fmt.Sprintf("expiring command '%s' on agent '%s'", cmd.Action.Name, cmd.Agent.Name)
			ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, CommandID: cmd.ID, ActionID: cmd.Action.ID, Desc: desc}
			cmd.Status = "expired"
			cmd.FinishTime = time.Now().UTC()
			// write it into the returned command directory
			data, err := json.Marshal(cmd)
			if err != nil {
				panic(err)
			}
			dest := fmt.Sprintf("%s/%.0f-%.0f.json", ctx.Directories.Command.Returned, cmd.Action.ID, cmd.ID)
			err = safeWrite(ctx, dest, data)
			if err != nil {
				panic(err)
			}
			//ctx.Directories.Command.Returned
			os.Remove(filename)
		}
	}
	dir.Close()
	return
}
Beispiel #2
0
// loadReturnedCommands walks through the returned commands directory and loads
// the commands into the scheduler
func loadReturnedCommands(ctx Context) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("loadReturnedCommands() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: "leaving loadReturnedCommands()"}.Debug()
	}()
	dir, err := os.Open(ctx.Directories.Command.Returned)
	dirContent, err := dir.Readdir(-1)
	if err != nil {
		panic(err)
	}
	// loop over the content of the directory
	for _, DirEntry := range dirContent {
		if !DirEntry.Mode().IsRegular() {
			// ignore non file
			continue
		}
		filename := ctx.Directories.Command.Returned + "/" + DirEntry.Name()

		if strings.HasSuffix(filename, ".fail") {
			// skip files with invalid commands
			continue
		}

		_, err = os.Stat(filename)
		if err != nil {
			// file is already gone, probably consumed by the file notifier
			// ignore and continue
			continue
		}
		err := waitForFileOrDelete(filename, 3)
		if err != nil {
			ctx.Channels.Log <- mig.Log{Desc: fmt.Sprintf("error while reading '%s': %v", filename, err)}.Err()
			continue
		}
		cmd, err := mig.CmdFromFile(filename)
		if err != nil {
			// failing to load this file, log and skip it
			ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: fmt.Sprintf("failed to load returned command file %s", filename)}.Err()
			continue
		}
		// queue it
		ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, CommandID: cmd.ID, ActionID: cmd.Action.ID, Desc: fmt.Sprintf("loading returned command '%s'", cmd.Action.Name)}
		ctx.Channels.CommandReturned <- filename
	}
	dir.Close()
	return
}
Beispiel #3
0
// returnCommands is called when commands have returned
// it stores the result of a command and mark it as completed/failed and then
// send a message to the Action completion routine to update the action status
func returnCommands(cmdFiles []string, ctx Context) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("returnCommands() -> %v", e)
		}
		ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: "leaving returnCommands()"}.Debug()
	}()
	for _, cmdFile := range cmdFiles {
		// load and parse the command. If this fail, skip it and continue.
		cmd, err := mig.CmdFromFile(cmdFile)
		if err != nil {
			// if CmdFromFile fails, rename the cmdFile and skip.
			desc := fmt.Sprintf("Command in %s failed, renaming to %s.fail", cmdFile, cmdFile)
			ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, Desc: desc}.Debug()
			os.Rename(cmdFile, cmdFile+".fail")
			continue
		}
		cmd.FinishTime = time.Now().UTC()
		// update command in database
		go func() {
			err = ctx.DB.FinishCommand(cmd)
			if err != nil {
				desc := fmt.Sprintf("command results insertion in database failed with error: %v", err)
				ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, ActionID: cmd.Action.ID, CommandID: cmd.ID, Desc: desc}.Err()
			} else {
				ctx.Channels.Log <- mig.Log{OpID: ctx.OpID, ActionID: cmd.Action.ID, CommandID: cmd.ID, Desc: "command updated in database"}.Debug()
			}

			// pass the command over to the Command Done channel
			ctx.Channels.CommandDone <- cmd
		}()
		// remove command from inflight dir
		inflightPath := fmt.Sprintf("%s/%.0f-%.0f.json", ctx.Directories.Command.InFlight, cmd.Action.ID, cmd.ID)
		os.Remove(inflightPath)

		// remove command from Returned dir
		os.Remove(cmdFile)
	}
	return
}
Beispiel #4
0
func main() {
	var err error
	var Usage = func() {
		fmt.Fprintf(os.Stderr,
			"Mozilla InvestiGator Action Verifier\n"+
				"usage: %s <-a action file> <-c command file>\n\n"+
				"Command line to verify an action *or* command.\n"+
				"Options:\n",
			os.Args[0])
		flag.PrintDefaults()
	}

	hasaction := false
	hascommand := false
	homedir := client.FindHomedir()

	// command line options
	var actionfile = flag.String("a", "/path/to/action", "Load action from file")
	var commandfile = flag.String("c", "/path/to/command", "Load command from file")
	var config = flag.String("conf", homedir+"/.migrc", "Load configuration from file")
	var showversion = flag.Bool("V", false, "Show build version and exit")
	flag.Parse()

	if *showversion {
		fmt.Println(mig.Version)
		os.Exit(0)
	}

	conf, err := client.ReadConfiguration(*config)
	if err != nil {
		panic(err)
	}

	// if a file is defined, load action from that
	if *actionfile != "/path/to/action" {
		hasaction = true
	}
	if *commandfile != "/path/to/command" {
		hascommand = true
	}
	if (hasaction && hascommand) || (!hasaction && !hascommand) {
		fmt.Println("[error] either an action file or a command file must be provided")
		Usage()
		os.Exit(1)
	}

	var a mig.Action
	if hasaction {
		a, err = mig.ActionFromFile(*actionfile)
		if err != nil {
			panic(err)
		}
	} else {
		c, err := mig.CmdFromFile(*commandfile)
		if err != nil {
			panic(err)
		}
		a = c.Action
	}

	err = a.Validate()
	if err != nil {
		fmt.Println(err)
	}

	pubringFile, err := os.Open(conf.GPG.Home + "/pubring.gpg")
	if err != nil {
		panic(err)
	}
	defer pubringFile.Close()

	// syntax checking
	err = a.VerifySignatures(pubringFile)
	if err != nil {
		fmt.Println("[error]", err)
	} else {
		fmt.Println("Valid signature")
	}

}