Codebase list stealth / e18e6b5
Imported Upstream version 2.10.00 tony mancill 11 years ago
48 changed file(s) with 411 addition(s) and 168 deletion(s). Raw diff Collapse all Expand all
4141 Groningen. Here are a PGP key server, and my PGP public key fingerprint:
4242
4343 Public PGP key: http://pgp.surfnet.nl:11371/
44 Key Fingerprint: 8E36 9FC4 1DAA FCDF 1A0D B19F DAC4 BE50 38C6 6170
44 Key Fingerprint: DF32 13DE B156 7732 E65E 3B4D 7DB2 A8BE EAE4 D8AA
4545
4646 Contact me if you have any doubts about the correctness of the provided
4747 signature or the given fingerprint.
0 Stealth has several modes of operation, defined in monitor/monitor.h, and
1 (partially) controlled by command-line options:
2
3 option mode meaning/action
4
5 default ONCE, single run in the foreground
6 keep-alive KEEP_ALIVE, multiple runs: Stealth becomes a daemon process
7
8 terminate TERMINATE, terminate a running Stealth daemon process
9 (through SIGTERM)
10 TERMINATED, automatically, following TERMINATE
11 suppress SUPPRESS, suppress a running Stealth daemon process,
12 (through SIGUSR1)
13 SUPPRESSED, automatically following SUPPRESS
14 resume resumes a SUPPRESSed Stealth daemon process
15 (through SIGUSR2)
16 reload RELOAD, a running Stealth daemon process reloads its
17 config files (through SIGCHLD)
18
19 All actions are controlled by Monitor::control, started by main(). This is the
20 only real action main performs.
21
22 Monitor:
23 control(): performs one infinite loop, in which the following actions
24 occur:
25
26 processMode() is called. It performs the actions associated with a
27 particular mode.
28 following this the report is mailed by mailReport().
29
30 Actions are s_mode-dependent.
31 The variable s_mode is global, and may be modified by daemon
32 process signal handlers:
33
34 s_mode =
35 ONCE: the foreground process ends.
36 TERMINATED: the daemon process ends.
37
38 SUPPRESSED: the daemon process is now in its suppressed state.
39 it sends a SUGUSR1 signal to the suppressing
40 process, and goes into suspend mode, from which it
41 awakes (at control()'s wait() call) when receiving
42 a resume (SIGUSR2) signal.
43
44 processMode() performs its own infinite loop, during which s_mode may
45 change. By default it calls Scanner::run() to perform a stealth-run.
0 #define VERSION "2.04.00"
0 #define VERSION "2.10.00"
11 #define YEARS "2005-2012"
0 ISN: stealth (2.10.00)
1
2 * --reload pidfile reloads the configuration files
3
4 * When specifying a directory with --skipfiles all entries below that
5 directory are skipped.
6
07 stealth (2.04.00)
18
29 * Added detection of invalid child process command texts: commands not
00 #include "configsorter.ih"
11
2 ConfigSorter::ConfigSorter(char const *confFile)
2 ConfigSorter::ConfigSorter(string const &confPath)
33 :
4 d_configfile(confFile),
5 d_use(&s_defaultKeyword[0], &s_defaultKeyword[s_nDefaultKeywords])
4 d_confPath(confPath)
65 {
7 fetchCommands();
8
9 string &base = d_use["BASE"];
10
11 base += "/."; // the . is required by mkdir
12
13 char const *cp = base.c_str();
14
15 if (!Util::mkdir(cp) || chdir(cp))
16 fmsg << "Can't chdir to `" << cp << '\'' << endl;
17
18 base.resize(base.length() - 1); // cut off the . again
6 reload();
197 }
208
219
1212
1313 class ConfigSorter
1414 {
15 std::string d_confPath;
1516 FBB::ConfigFile d_configfile;
1617 std::vector<std::string> d_command;
1718 FBB::HashString<std::string> d_use;
2526 // [1]: all ${NAME} text
2627 // [2]: NAME itself
2728 public:
28 ConfigSorter(char const *confFname);
29 ConfigSorter(std::string const &confPath);
30
31 void reload();
2932
3033 std::vector<std::string>::const_iterator firstCmd() const;
3134 std::vector<std::string>::const_iterator beyondCmd() const;
0 #include "configsorter.ih"
1
2 void ConfigSorter::reload()
3 {
4 d_configfile.open(d_confPath);
5
6 d_use = HashString<std::string>
7 (&s_defaultKeyword[0], &s_defaultKeyword[s_nDefaultKeywords]);
8
9 d_define.clear();
10 d_command.clear();
11
12 fetchCommands();
13
14 string &base = d_use["BASE"];
15
16 base += "/."; // the . is required by mkdir
17
18 char const *cp = base.c_str();
19
20 if (!Util::mkdir(cp) || chdir(cp))
21 fmsg << "Can't chdir to `" << cp << '\'' << endl;
22
23 base.resize(base.length() - 1); // cut off the . again
24 }
25
26
27
587587 it() tt(-q --quiet): Suppress progress messages written to stderr;
588588 it() tt(-r --run-command <nr>): Only run command <nr> (natural number).
589589 Command numbers are shown by s() tt(-c);
590 it() tt(-s --skip-files <skippath>): All files mentioned in tt(skippath)
591 (using an absolute path) are skipped. Their integrity is not monitored. If a
592 file is already present in a log file then s() will once generate an
593 tt(IGNORING) message in the mail sent to the address specified at tt(EMAIL) in
594 the policy file. Each file mentioned in tt(filepath) must be on a line of
595 its own and must be specified using absolute file paths. Initial and trailing
596 blanks, empty lines and lines having a tt(#) as their 1st non blank character
597 are ignored.
590 it() tt(-s --skip-files <skippath>): All entries in tt(skippath)
591 (specified using an absolute path) are skipped. Their integrity is not
592 monitored. If an entry is already present in a log file then s() will once
593 generate an tt(IGNORING) message in the mail sent to the address specified at
594 tt(EMAIL) in the policy file. Each entry mentioned in tt(filepath) must be on a
595 line of its own and must be specified using absolute paths. Entries ending in
596 a slash are assumed to be directories whose contents must be skipped. Other
597 entries are interpreted as the path names of files to skip. Initial and
598 trailing blanks, empty lines and lines having a tt(#) as their 1st non blank
599 character are ignored. If the
598600 it() tt(-v --version): Display version information and exit;
599601 it() tt(--keep-alive pidfile): Keep running as a daemon,
600602 wake up at interrupts.
606608 interrupts or after <seconds> seconds. The interval will be at
607609 least 60 seconds. To this interval a random delay may be added
608610 (see tt(--random-interval)).
611 it() tt(--reload pidfile): reloads the configuration and skip-files and
612 restarts the scan of a currently active s() process.
609613 it() tt(--rerun pidfile): restart the scan of a currently active s()
610614 process;
611615 it() tt(--resume pidfile): resume a suppressed s()
6767 sent when no changes were detected.
6868 )
6969
70 Alternatively, the command-line options tt(--rerun) and tt(--terminate)
71 may be provided to communicate with a bf(stealth) process started earlier
72 using either the tt(--keep-alive) or tt(--repeat) option. In this case,
70 Alternatively, the command-line options tt(--reload, --rerun, --suppress,
71 --resume) and tt(--terminate) may be provided to communicate with a running
72 bf(stealth) process started earlier using either the tt(--keep-alive) or
73 tt(--repeat) option. For these options one argument must be provided: the
74 pathname to a pid-file of a running s().
7375 itemization(
7476 it() When started using the tt(--terminate <pid>) command-line option, the
75 stealth process running at process-ID tt(<pid>) is terminated. Note that no
76 check is performed as to whether the process associated with tt(<pid>) is
77 truly a bf(stealth) process. It is the responsibility of the user to make sure
78 that the process-ID of the intended process is specified.
77 stealth process running at process-ID tt(<pid>) is terminated.
78 it() When started using the tt(--reload <pid>) command-line option, the
79 stealth process running at process-ID tt(<pid>) will reload its configuration
80 and skip-files, which is then immediately followed by another stealth
81 scan.
7982 it() When started using the tt(--rerun <pid>) command-line option, the
8083 stealth process running at process-ID tt(<pid>) will perform another
81 scan. Again, no check is performed as to whether the process associated with
82 tt(<pid>) is truly a bf(stealth) process. It is the responsibility of the user
83 to make sure that the process-ID of the intended process is specified.
84 scan.
8485 )
8586
8687 The options tt(--suppress) and tt(--rerun) (see section ref(ROTATE)) were
108109 )
109110 it() Make sure you have the right key. Its fingerprint is
110111 verb(
111 8E36 9FC4 1DAA FCDF 1A0D B19F DAC4 BE50 38C6 6170
112 DF32 13DE B156 7732 E65E 3B4D 7DB2 A8BE EAE4 D8AA
112113 )
113114 and it has been electronically signed by, e.g., the University of
114115 Groningen's PGP-certificate authority. If in doubt, contact me to verify you
123124 )
124125 This should produce output comparable to:
125126 verb(
126 gpg: Signature made Mon Aug 1 10:57:41 2005 CEST using DSA key ID 38C66170
127 gpg: Signature made Fri Jun 1 10:57:41 2012 CEST using DSA key ID EAE4D8AA
127128 gpg: Good signature from "Frank B. Brokken <f.b.brokken@rug.nl>"
128 gpg: aka "Frank B. Brokken <f.b.brokken@rc.rug.nl>"
129129 )
130130
131131
132
133
0 Some files may not require integrity checks. Automated processes may modify
1 files which are not threatening the proper functioning of running programs or
2 processes. In those cases a file can be prepared holding the absolute paths of
3 files that can be skipped. Each file should appear on a line of its own
4 without any additional information.
0 Some files or directories may not require integrity checks. Automated
1 processes may modify files which are not threatening the proper functioning of
2 running programs or processes. In those cases a file can be prepared holding
3 the absolute paths of entries to be skipped. Each entry should appear on a
4 line of its own without any additional information.
55
66 bf(Stealth) can be informed about this file using the tt(-s skippath) or
7 tt(--skip-files skippath) option. The file holding the paths of the files to
8 be skipped should be specified using absolute paths, one file per
7 tt(--skip-files skippath) option. The file holding the paths of the entries to
8 be skipped should be specified using absolute paths, using one entry per
99 line. Initial and trailing blanks, empty lines and lines having a tt(#) as
1010 their first non blank character are ignored.
1111
1414 stealth -e --skip-files /root/stealth/remote/skipping remote.pol
1515 )
1616
17 If a file tt(/etc/skipme) appears in the current logs which is thereafter
17 If an entry tt(/etc/skipme) appears in the current logs which is thereafter
1818 added to the tt(skippath) file then the mail generated by bf(stealth) will
1919 once contain a line like the following:
2020 verb(
2323 )
2424 The shown hash-value is the hash-value at the time of the stealth-run
2525 reporting the tt(SKIPPING) message.
26
27 Entries ending in a slash are assumed to be directories whose contents must be
28 skipped.
11
22 void Monitor::contactOtherStealth()
33 {
4 Arg &arg = Arg::instance();
4 if (d_arg.option(0, "reload"))
5 signalStealth(SIGPIPE, "SIGPIPE", d_arg[0]);// signalStealth calls
6 // end the current process
7 if (d_arg.option(0, "rerun"))
8 signalStealth(SIGHUP, "SIGHUP", d_arg[0]);
59
6 if (arg.option(0, "rerun"))
7 signalStealth(SIGHUP, "SIGHUP", arg[0]); // all signalStealth calls
8 // end the current process
10 if (d_arg.option(0, "terminate"))
11 signalStealth(SIGTERM, "SIGTERM", d_arg[0]);
912
10 if (arg.option(0, "terminate"))
11 signalStealth(SIGTERM, "SIGTERM", arg[0]);
12
13 if (arg.option(0, "suppress"))
14 lock(arg[0]); // lock locally, let the
13 if (d_arg.option(0, "suppress"))
14 lock(d_arg[0]); // lock locally, let the
1515 // integrity wait, exits
16 if (arg.option(0, "resume"))
17 signalStealth(SIGUSR2, "SIGUSR2", arg[0]);
16 if (d_arg.option(0, "resume"))
17 signalStealth(SIGUSR2, "SIGUSR2", d_arg[0]);
1818 }
1919
2020
22 // Called by main() once all preliminary actions have been completed. This
33 // function controls the processing of the configuration file.
44
5 // Signals are sent by sendSignal. Signals are caught by handleProcessSignals
6 // contactOtherStealth sends the signals depending on command-line options
7
58 void Monitor::control()
69 {
710 while (true)
811 {
9 imsg << "CONTROL: s_mode == " << s_mode << endl;
12 imsg << "CONTROL: s_mode == " << s_modeID[s_mode] << endl;
1013
1114 d_reporter->standby(); // locks the runfile, opens the report
1215 // file
2023 // command returns a non-zero exit value.
2124 if (s_mode == TERMINATED || s_mode == ONCE)
2225 break;
26
27 if (s_mode == RELOAD)
28 {
29 s_mode = KEEP_ALIVE;
30 continue;
31 }
2332
2433 if (s_mode == SUPPRESSED)
2534 {
5059 while (s_mode == SUPPRESSED);
5160 }
5261 }
62
77 size_t Monitor::s_delayInterval = 0;
88 size_t Monitor::s_repeatInterval = 0;
99
10 // Update this array if Mode definitions in monitor.h change
11 char const *const Monitor::s_modeID[] =
12 {
13 "ONCE",
14 "KEEP",
15 "TERMINATE",
16 "TERMINATED",
17 "SUPPRESS",
18 "SUPPRESSED",
19 "RELOAD"
20 };
22 void Monitor::handleKeepAliveOption()
33 {
44 string value;
5 if ((s_keepAlive = Arg::instance().option(&value, "keep-alive")) != 0)
5 if ((s_keepAlive = d_arg.option(&value, "keep-alive")) != 0)
66 {
7 s_repeatInterval = INT_MAX;
7 s_repeatInterval = numeric_limits<int>::max();
88 Lock::setRunFilename(value);
99 }
1010 }
2727 if (s_mode == SUPPRESS || s_mode == SUPPRESSED)
2828 s_mode = KEEP_ALIVE;
2929 break;
30
31 case SIGPIPE: // RELOAD: changes KEEP_ALIVE
32 if (s_mode == KEEP_ALIVE) // temporarily into RELOAD
33 s_mode = RELOAD; // for processMode() to handle.
34 break;
35
36 default:
37 return;
3038 }
3139
3240 wakeup();
3341 signal(signum, handleProcessSignals);
3442 }
43
11
22 void Monitor::handleRepeatOption()
33 {
4 Arg &arg = Arg::instance();
5
64 string value;
75
8 if (arg.option(&value, "repeat"))
6 if (d_arg.option(&value, "repeat"))
97 {
108 if (!s_keepAlive)
119 fmsg << "--repeat requires --keep-alive" << endl;
2220 '\'' << endl;
2321 s_repeatInterval = s_shortestRepeatInterval;
2422 }
25 else if (s_repeatInterval > INT_MAX)
26 s_repeatInterval = INT_MAX;
23 else if (s_repeatInterval >
24 static_cast<size_t>(numeric_limits<int>::max()))
25 s_repeatInterval = numeric_limits<int>::max();
2726 }
2827 }
2928
1111 return;
1212 }
1313
14 d_reporter->rewind(); // resets the `hasmail' variable
14 d_reporter->rewind(); // resets the `hasmail' variable
1515
16 if (Arg::instance().option('o')) // mail the report to stdout
16 if (d_arg.option('o')) // mail the report to stdout
1717 {
1818 imsg << "Monitor::mailReport() mails report to stdout" << endl;
1919 cout << d_reporter->in().rdbuf() << endl;
00 #include "monitor.ih"
11
22 Monitor::Monitor()
3 :
4 d_arg(Arg::instance()),
5 d_sorterPath(Util::makeAbsPath(d_arg[0]))
36 {
47 processControlOptions(); // handle process control options
58 maybeBackground(); // maybe run Stealth in the background
1316 signal(SIGTERM, Monitor::handleProcessSignals);
1417 signal(SIGUSR1, Monitor::handleProcessSignals);
1518 signal(SIGUSR2, Monitor::handleProcessSignals);
19 signal(SIGPIPE, Monitor::handleProcessSignals);
1620 }
1721
1822
77 namespace FBB
88 {
99 class Selector;
10 class Arg;
1011 }
1112
1213 class ConfigSorter;
1516
1617 class Monitor
1718 {
19 // Update s_modeID in data.cc if the following enum changes:
1820 enum Mode
1921 {
22 // These numbers are here for debug output referential
23 // purpose only. Their values are not otherwise used
2024 ONCE, // 0 single run
2125 KEEP_ALIVE, // 1 multiple runs
2226 TERMINATE, // 2 through SIGTERM
2327 TERMINATED, // 3 automatically following TERMINATE
2428 SUPPRESS, // 4 through SIGUSR1 (SIGUSR2: back to normal)
2529 SUPPRESSED, // 5 automatically following SUPPRESS
30 RELOAD, // 6 reload the config files, through SIGPIPE
2631 };
2732
33 static char const *const s_modeID[];
2834 static Mode s_mode;
2935 static bool s_quit; // passed to Scanner::run() for
3036 // inspection
3137
38 FBB::Arg &d_arg;
39
40 std::string d_sorterPath;
3241 std::unique_ptr<ConfigSorter> d_sorter;
3342 std::unique_ptr<Reporter> d_reporter;
3443 std::unique_ptr<Scanner> d_scanner;
5665 static void handleProcessSignals(int signum);
5766
5867 private:
59
68 void reload(); // reload the configuration files.
6069 void processMode(); // process the current mode
6170 void processControlOptions(); // determine the running mode
6271 void contactOtherStealth();
11
22 #include <string>
33 #include <signal.h>
4 #include <limits>
45
56 #include <bobcat/arg>
67 #include <bobcat/process>
89 #include <bobcat/errno>
910 #include <bobcat/datetime>
1011
12 #include "../util/util.h"
1113 #include "../lock/lock.h"
1214 #include "../configsorter/configsorter.h"
1315 #include "../scanner/scanner.h"
1416 #include "../reporter/reporter.h"
1517
16
18 using namespace std;
1719 using namespace FBB;
18 using namespace std;
1920
2021 inline void Monitor::wakeup()
2122 {
77 {
88 switch (s_mode)
99 {
10 default:
11 d_scanner->run(&s_quit);
12
13 if (s_mode == TERMINATE || s_mode == SUPPRESS)
14 continue;
15 return;
16
17 case RELOAD:
18 *d_reporter <<
19 "STEALTH reloads its configuration files after " <<
20 d_scanner->nScans() << " scans at " << now << endl;
21 reload();
22 return; // next cycle: rerun a scan.
23
1024 case TERMINATE:
1125 *d_reporter <<
1226 "STEALTH was terminated after " << d_scanner->nScans() <<
2539 case SUPPRESSED:
2640 return;
2741
28 default:
29 d_scanner->run(&s_quit);
30
31 if (s_mode == TERMINATE || s_mode == SUPPRESS)
32 continue;
33 return;
3442 }
3543 }
3644 }
33 {
44 string delay;
55
6 if (!Arg::instance().option(&delay, 'i'))
6 if (not Arg::instance().option(&delay, 'i'))
77 return;
88
9 if (!Arg::instance().option(0, "repeat"))
9 if (not Arg::instance().option(0, "repeat"))
1010 {
1111 wmsg << "--random-interval ignored unless --repeat is specified" <<
1212 endl;
0 #include "monitor.ih"
1
2 void Monitor::reload()
3 {
4 d_sorter->reload();
5 d_scanner.reset( new Scanner(*d_sorter, *d_reporter) );
6
7 // ->nScansReset();
8 // d_scanner->loadSkipFiles();
9
10 d_scanner->preamble();
11
12 // cerr << "RELOAD COMPLETED (" << d_sorterPath << ")\n";
13 }
14
15
66 // is removed and an error message is issued.
77
88 // The following signals are used (and processed by Scanner::processSignal())
9 // SIGPIPE: reload configuration files
910 // SIGTERM: terminate stealth
1011 // SIGHUP: rerun stealth
1112 // SIGUSR1: suppress stealth from starting a new run
11
22 void Monitor::sleep()
33 {
4 s_selector.setAlarm(INT_MAX);
4 s_selector.setAlarm(numeric_limits<int>::max());
55 }
11
22 void Monitor::startStealth()
33 {
4 d_sorter.reset( new ConfigSorter(Arg::instance()[0]) );
5 d_reporter.reset(new Reporter((*d_sorter)["REPORT"]));
6 d_scanner.reset(new Scanner(*d_sorter, *d_reporter));
4 d_sorter.reset( new ConfigSorter(d_sorterPath) );
5 d_reporter.reset( new Reporter((*d_sorter)["REPORT"]) );
6 d_scanner.reset( new Scanner(*d_sorter, *d_reporter) );
77
88 handleKeepAliveOption();
99 handleRepeatOption();
1010
1111 imsg << "Scanner::copy(): about to read child input" << endl;
1212
13 string s;
13 string line;
1414 off_t length = 0;
15 while (getline(src, s))
15 while (getline(src, line))
1616 {
17 if (!checkSize(fname, length += s.length() + 1))
17 if (!checkSize(fname, length += line.length() + 1))
1818 return;
1919
20 imsg << "copy SAW: `" << s << '\'' << endl;
20 imsg << "copy SAW: `" << line << '\'' << endl;
2121
22 if (s.find(d_sentinel) == 0)
22 if (line.find(d_sentinel) == 0)
2323 {
2424 imsg << "GOT Sentinel" << endl;
2525 break;
2626 }
2727
28 if (not (this->*d_skip)(s))
29 currentReport << s << '\n';
28 s_split << line; // get the last word on this line
29 string last = s_split[1];
30
31 if (not (this->*d_skip)(last))
32 currentReport << line << '\n';
3033 }
31 testExitValue(src.str(), s);
34 testExitValue(src.str(), line);
3235 }
3336
3437
1111
1212 imsg << "running checked command: `" << s_firstWord[0] << '\'' << endl;
1313
14 if (Arg::instance().option('n')) // -n (no go) option?
14 if (d_arg.option('n')) // -n (no go) option?
1515 return true; // then indicate by implication that
1616 // the command was processed without
1717 // differing from the previous run
22 void Scanner::doPlainCommand(Process &child)
33 {
44 imsg << "running unchecked command: `" << s_firstWord[0] << '\'' << endl;
5 if (!Arg::instance().option('n')) // unless -n (no execute commands)
5 if (!d_arg.option('n')) // unless -n (no execute commands)
66 {
77 nextCommand(child, s_firstWord[0]); // start the next command
88 waitForSentinel(child); // read its output
55 if (!(s_firstWord << cmd)) // determine first word and the rest
66 d_reporter.error() << "Corrupt line in policy file: " << cmd << endl;
77
8 if (Arg::instance().option("de"))// echo the command with -d, -e
8 if (d_arg.option("de")) // echo the command with -d, -e
99 cerr << *d_cmdIterator << '\n';
1010
1111 if (s_firstWord[1] == "LABEL") // set a label
3838 imsg << "Scanner::get(): scp <client>:" << source << " " <<
3939 destination << endl;
4040
41 if (Arg::instance().option('n')) // no run if -n
41 if (d_arg.option('n')) // no run if -n
4242 return;
4343
4444 nextCommand(d_sshFork, // start the next command
0 #include "scanner.ih"
1
2 void Scanner::loadSkipFiles()
3 {
4 d_skipFiles.clear();
5
6 if (d_skipFilePath.length()) // skip files
7 setSkip();
8 else // or don't skip
9 d_skip = &Scanner::dontSkip;
10
11 imsg << "Scanner::loadSkipFiles(): " << d_skipFiles.size() <<
12 "lines" << endl;
13 }
14
15
16
17
18
19
20
21
2424 imsg << "Scanner::noDifferences(): /bin/echo " << d_sentinel <<
2525 endl;
2626
27 // key is string, case sensitive.
27 // status's key is a case sensitive string.
2828 //
2929 // The last element of the lines produced by diff is used as the
3030 // key. For the current function to operate sensibly, this should be
31 // a filename or path/file.
31 // a filename or a path/file.
3232 //
3333 // If the first character of the line is a < or >, then a modification is
3434 // detected: for these lines the following happens:
35 // 1. If the key already existed its .first element is set to
36 // "modified". If the key didn't exist yet, it is set to
37 // "added" at at '<'. It is set to "skipping" at a '>' if the
38 // pathname is found in the array of files to skip. Otherwise
35 // 1. If the key already exists then its .first element is set to
36 // "modified". When a '<' was seen and if the key doesn't yet
37 // exist, it is set to "added".
38 // If the pathname is found in the array of files to skip
39 // or if the pathname truncated at the last '/' is found in the
40 // d_skipFiles array it is set to "skipping". Otherwise
3941 // it's set to "removed".
4042 // 2. The line itself is pushed back to the .second (vector) element
4143 // of the pair.
4446 // into the d_reporter and `false' is returned. If the hashtable contains
4547 // no elements, 'true' is returned.
4648
47 string s;
49 string line;
4850
4951 imsg << "Scanner::noDifferences(): starting to read lines" << endl;
5052
51 while (getline(d_shFork, s))
53 // get lines from diff, lines like:
54 //
55 // 33c33
56 // < 90d8b506d249634c4ff80b9018644567 out
57 // ---
58 // > b88d0b77db74cc4a742d7bc26cdd2a1e out
59
60 while (getline(d_shFork, line))
5261 {
53 imsg << "Scanner::noDifferences(): got: `" << s << "'\n"
62 imsg << "Scanner::noDifferences(): got: `" << line << "'\n"
5463 "Scanner::noDifferences(): sentinel: `" << d_sentinel << '\'' <<
5564 endl;
56 if (s == d_sentinel)
65 if (line == d_sentinel) // done at the sentinel
5766 break;
5867
59 if (!(s_split << s))
60 continue; // no match at empty lines ?
68 if (not (s_split << line)) // at empty lines proceed to the
69 continue; // next line
6170
62 string key = s_split[1]; // get the key
63 bool exists = status.count(key);
71 string lastWord = s_split[1]; // get the last word on lines
72 // the last word may be an element of a directory to skip or
73 // not. If it is an element of a directory to skip, then the
74 // filename part of lastWord kan be removed.
6475
65 if (s[0] == '<')
66 status[key].first = exists ? "MODIFIED" : "ADDED";
67 else if (s[0] == '>') // removal or skip, e.g., > b88d0b.... out
68 {
69 if ((this->*d_skip)(key))
70 status[key].first = "SKIPPING";
71 else
72 status[key].first = exists ? "MODIFIED" : "REMOVED";
73 }
76 // find out whether we have to skip this entry or not. If so
77 // remove the filename from lastWord:
78 bool skipEntry = (this->*d_skip)(lastWord);
79
80 // now we'll process skipped elements by their path-name
81 // and other elements remain as-is
82 bool exists = status.count(lastWord);
83
84 if (line[0] == '<')
85 status[lastWord].first = exists ? "MODIFIED" : "ADDED";
86 else if (line[0] == '>') // removal or skip, e.g., > b88d0b.... out
87 status[lastWord].first = skipEntry ? "SKIPPING" :
88 exists ? "MODIFIED" : "REMOVED";
7489 else
7590 continue;
7691
77 status[key].second.push_back(s);
92 status[lastWord].second.push_back(line);
7893 }
7994
8095 if (!status.size()) // no elements ?
3737
3838 string command = putCommand(source, destination);
3939
40 if (Arg::instance().option('n')) // no run if -n
40 if (d_arg.option('n')) // no run if -n
4141 return;
4242
4343 d_sshFork << command << endl; // flush
1111 // add values to it, below.
1212 string cmdNr;
1313
14 if (Arg::instance().option(&cmdNr, 'r')) // is there a command number?
14 if (d_arg.option(&cmdNr, 'r')) // is there a command number?
1515 {
1616 // if so, add its number to
1717 // d_cmdIterator
3737 }
3838 }
3939
40 if (Arg::instance().option('d'))
40 if (d_arg.option('d'))
4141 cerr << "Stealth: policy file processed\n";
4242 }
4343
1010
1111 Scanner::Scanner(ConfigSorter &sorter, Reporter &reporter)
1212 :
13 d_arg(Arg::instance()),
1314 d_sorter(sorter),
1415 d_reporter(reporter), // ostream
1516 d_firstWord(*new Pattern("(\\S+)(\\s+(.*))?")), // firstword ([1]) and the
3435 {
3536 setSentinel();
3637
37 Arg &arg = Arg::instance();
38 d_arg.option(&d_skipFilePath, 's');
3839
39 string name;
40 if (arg.option(&name, 's')) // skip files
41 setSkip(name);
42 else // or skip none
43 d_skip = &Scanner::dontSkip;
40 loadSkipFiles();
4441
45 if (arg.option(&d_maxSizeStr, "max-size"))
42 if (d_arg.option(&d_maxSizeStr, "max-size"))
4643 {
4744 d_maxSize = A2x(d_maxSizeStr);
4845 switch(d_maxSizeStr.find_first_not_of("0123456789"))
99 namespace FBB
1010 {
1111 class Pattern;
12 class Arg;
1213 }
1314
1415 class ConfigSorter;
1920 typedef std::vector<std::string> StringVector;
2021 typedef StringVector::const_iterator const_iterator;
2122
23 FBB::Arg &d_arg;
2224 ConfigSorter &d_sorter;
2325 Reporter &d_reporter;
2426 FBB::Pattern &d_firstWord;
3335 std::string d_maxSizeStr;
3436 bool d_quit;
3537 StringVector d_skipFiles;
38 std::string d_skipFilePath;
3639 // the abs path is at the end of
3740 // the line. Any text may precede
3841 // it
39 bool (Scanner::*d_skip)(std::string const &absPath);
42 bool (Scanner::*d_skip)(std::string &absPath);
4043
4144 static FBB::Pattern s_split;
4245 static FBB::Pattern s_firstWord;
4952 return d_nScans;
5053 }
5154 void preamble();
55 void loadSkipFiles();
56 void nScansReset();
5257 // run one series of tests
5358 void run(volatile bool *done);
5459
138143 void removeLOG(); // remove LOG = from current command
139144
140145 // true if filename not in d_skipFiles
141 bool skip(std::string const &line);
146 bool skip(std::string &line);
142147
143148 // always indicates "don't skip"
144 bool dontSkip(std::string const &line);
149 bool dontSkip(std::string &line);
145150
146151 // fill the d_skipFiles vector and set
147 // d_skip to &skipING
148 void setSkip(std::string const &fname);
152 void setSkip(); // d_skip to &skipING
149153
150154 static std::string fileName(std::string const &name);
151155 static std::string datetime();
154158 static void add(std::string const &line, StringVector &skipFiles);
155159 };
156160
157 inline bool Scanner::dontSkip(std::string const &line)
161 inline void Scanner::nScansReset()
158162 {
159 return false; // by returning false the question
160 // 'skip line?' is always answered as 'no'
163 d_nScans = 0;
161164 }
162165
163166 #endif
1414 #include <bobcat/stat>
1515 #include <bobcat/datetime>
1616 #include <bobcat/string>
17 #include <bobcat/stringline>
1718
1819 #include "../util/util.h"
1920 #include "../configsorter/configsorter.h"
2021 #include "../reporter/reporter.h"
2122
23 using namespace std;
24 using namespace FBB;
2225
23 using namespace FBB;
24 using namespace std;
25
26 struct Line: public string
27 {};
28
29
30 inline istream &operator>>(istream &in, Line &line)
26 inline bool Scanner::dontSkip(std::string &line)
3127 {
32 return getline(in, line);
28 return false; // by returning false the question
29 // 'skip line?' is always answered as 'no'
3330 }
3431
35
36
37
38
00 #include "scanner.ih"
11
2 void Scanner::setSkip(string const &fname)
2 void Scanner::setSkip()
33 {
44 ifstream in;
5 Errno::open(in, fname);
5 Errno::open(in, d_skipFilePath);
66
77 for_each(
8 istream_iterator<Line>(in), istream_iterator<Line>(),
8 istream_iterator<StringLine>(in), istream_iterator<StringLine>(),
99 [&](std::string const &line)
1010 {
1111 add(line, d_skipFiles);
1212 }
1313 );
14
14
1515 d_skip = &Scanner::skip;
1616 }
1717
00 #include "scanner.ih"
11
2 bool Scanner::skip(string const &line)
2 // line: the last entry of lines like
3 // 9fd210eed1190870f69c9bc7544cfacb82099efd /root/aantekeningen
4 // so:
5 // /root/aantekeningen
6 //
7 // toSkip: a line from the `skipfiles' file
8 // Files are skipped if:
9 // 1. the filename in `line' equals toSkip: equal filenames
10 // 2. the filename in `line' begins with toSkip and toSkip and
11 // toSkip ends in /: toSkip is a directory, and line is an
12 // entry in that directory
13
14 bool Scanner::skip(string &lastWord)
315 {
416 auto end = d_skipFiles.end();
517 return find_if(
618 d_skipFiles.begin(), end,
7 [&](string const &targetLine)
19 [&](string const &toSkip) // toSkip: entry to skip
820 {
9 size_t idx = line.rfind(targetLine);
10 return idx + targetLine.length() == line.length();
21 if (lastWord == toSkip) // lastWord contains toSkip
22 return true; // skip this file
23
24 if (toSkip.back() != '/') // toSkip isn't a dir.:
25 return false; // don't skip this entry
26
27 // skip this entry and remove the filename from
28 // 'lastWord' if lastWord contains toSkip at 0
29 if (lastWord.find(toSkip) == 0)
30 {
31 lastWord = toSkip;
32 return true;
33 }
34
35 return false; // don't skip this entry
1136 }
1237 )
1338 != end;
66
77 namespace{
88
9 Arg::LongOption longOpt_begin[] =
9 Arg::LongOption longOption[] =
1010 {
1111 {"debug", 'd'},
1212 {"echo-commands", 'e'},
2727 {"rerun", Arg::None}, // arg[0] is the runfilename
2828 {"resume", Arg::None}, // also for this and the next options
2929 {"suppress", Arg::None},
30 {"reload", Arg::None},
3031 {"terminate", Arg::None},
3132 };
3233
33 Arg::LongOption const * const longOpt_end =
34 longOpt_begin + sizeof(longOpt_begin) / sizeof(Arg::LongOption);
34 auto endLongOption = longOption + sizeof(longOption) / sizeof(longOption[0]);
3535
3636 } // anonymous namespace ends
3737
3838 int main(int argc, char **argv)
3939 try
40 {
41 // construct Arg object to process
42 Arg &arg = Arg::initialize("cdehi:noqr:s:v", longOpt_begin, longOpt_end,
40 { // construct Arg object to process
41 Arg &arg = Arg::initialize("cdehi:noqr:s:v", longOption, endLongOption,
4342 argc, argv);
4443
4544 arg.versionHelp(usage, version, 1);
0 # set up the non-default USE variables
1 USE BASE /home/frank/stealth/
2
3 USE EMAIL frank@localhost
4 USE MAILER /usr/bin/mail
5 USE MAILARGS -s "localhost STEALTH report"
6
7 USE SSH /usr/bin/ssh frank@localhost -q
8
9
10 LABEL \nfiles in /home/frank/documents/reizen
11 CHECK remote/reizen \
12 /usr/bin/find /home/frank/documents/reizen \
13 -type f -exec /usr/bin/sha1sum {} \;
0 /home/frank/documents/reizen/esta/
0 ../tmp/bin/stealth
5151 " policy: path to the policyfile\n"
5252 "\n"
5353 "Usage 2:\n"
54 " " << progname << " [--rerun|--resume|--suppress|--terminate] "
55 "pidfile\n"
54 " " << progname <<
55 " [--reload|--rerun|--resume|--suppress|--terminate] pidfile\n"
5656 "Where:\n"
57 " --reload: reload a " << progname << " process's configuration "
58 "files\n"
5759 " --rerun: restart a " << progname << " integrity scan\n"
5860 " --resume: resume " << progname << " following --suppress\n"
5961 " --suppress: suppress " << progname << " activities\n"
0 #include "util.ih"
1
2 string Util::makeAbsPath(string const &path)
3 {
4 string ret;
5
6 if (path[0] == '/')
7 ret = path;
8 else
9 ret = Stat(".").path() + '/' + path;
10
11 return ret;
12 }
55 class Util
66 {
77 public:
8 static bool mkdir(std::string const &path); // pathname to a file
8 static bool mkdir(std::string const &path); // pathname to a file
9 // find full path name
10 static std::string makeAbsPath(std::string const &path);
11
912 };
1013
1114 #endif
00 #include "util.h"
11
2 #include <ostream>
23 #include <string>
3 #include <ostream>
44
55 #include <libgen.h>
66 #include <sys/stat.h>
77 #include <sys/types.h>
88
9 #include <bobcat/stat>
10
911 using namespace std;
12 using namespace FBB;