Imported Upstream version 4.00.00
tony mancill
9 years ago
0 | syslogstruct | |
1 | ||
0 | 2 | msg |
1 | 3 | |
2 | wait11 msg | |
4 | util | |
3 | 5 | |
4 | util | |
5 | 6 | stealthenums |
6 | 7 | |
7 | options stealthenums msg util | |
8 | options stealthenums syslogstruct msg util | |
8 | 9 | |
9 | policyfile options | |
10 | runmode options | |
11 | stealthlog options | |
10 | policyfile options | |
12 | 11 | |
13 | integrityscanner options policyfile stealthlog runmode | |
12 | runmode stealthenums | |
14 | 13 | |
15 | ipc options wait11 | |
14 | report policyfile | |
16 | 15 | |
17 | stealth integrityscanner ipc stealthlog | |
16 | integrityscanner policyfile runmode | |
17 | ||
18 | logunit options | |
19 | ||
20 | stealth logunit integrityscanner report | |
21 | ||
18 | 22 | |
19 | 23 | |
20 | 24 |
0 | 0 | // Specify the name of the project: |
1 | 1 | #define PROJECT "stealth" |
2 | 2 | |
3 | // When defined, these overrule COMPILER and COMPILER_OPTIONS | |
4 | // COMPILER and COMPILER_OPTIONS are now obsolete | |
5 | // Instead of CXX and CXXFLAGS, CC and CFLAGS can be used. | |
6 | // Their #define values are overruled by identically named environment | |
7 | // variables. | |
3 | // Compiler to use: | |
4 | #define CXX "g++" | |
5 | //#define CXX "g++-5" | |
8 | 6 | |
9 | #define CXX "g++" | |
10 | // the compiler to use. | |
7 | // The compiler options to use: | |
8 | #define CXXFLAGS "--std=c++14 -Wall -O2 -pthread" | |
11 | 9 | |
12 | #define CXXFLAGS "--std=c++11 -Wall -O2 -pthread -g" | |
13 | // the compiler options to use. | |
10 | // Flags passed to the linker: | |
11 | #define LDFLAGS "-lpthread" | |
14 | 12 | |
15 | #define LDFLAGS "-lpthread" | |
16 | // flags passed to the linker | |
13 | // The following locations can be overruled by `build install' arguments | |
17 | 14 | |
18 | // ========================================================================= | |
19 | // The following locations are overruled by `build install' arguments | |
15 | // the full path of the final program | |
16 | #define BINARY "/usr/bin/"${PROJECT} | |
20 | 17 | |
21 | #define BINARY "/usr/bin/"${PROJECT} | |
22 | // the full path of the final program | |
18 | // the directory whre the manual page is stored | |
19 | #define MAN "/usr/share/man/man1" | |
23 | 20 | |
24 | #define MAN "/usr/share/man/man1" | |
25 | 21 | // the directory whre the manual page is stored |
22 | #define MANUAL "/usr/share/doc/"${PROJECT}"-doc/manual" | |
26 | 23 | |
27 | #define MANUAL "/usr/share/doc/"${PROJECT}"-doc/manual" | |
28 | // the directory whre the manual page is stored | |
24 | // the directory where the standard documentation is stored | |
25 | #define STD "/usr/share/doc/"${PROJECT} | |
29 | 26 | |
30 | #define STD "/usr/share/doc/"${PROJECT} | |
31 | // the directory where the standard documentation is stored | |
32 | ||
27 | // the directory where the extra documentation is stored | |
33 | 28 | #define EXTRA "/usr/share/doc/"${PROJECT}"-doc" |
34 | // the directory where the extra documentation is stored | |
35 | 29 | |
36 | 30 | |
37 | 31 |
0 | With Stealth 4.00.00 existing policy files used with Stealth 3.00.00 can | |
1 | remain as-is, although a run- or pid-file is no longer used. Instead, a Unix | |
2 | Domain Socket is used for communication between a Stealth daemon and Stealth | |
3 | running in IPC mode. | |
4 | ||
5 | For cosmetic reasons consider using xxx.uds instead of xxx.run or xxx.pid. | |
6 | ||
7 | Logrotate.d scripts should use the 'copytruncate' and 'sharedscripts' options | |
8 | (see the man-page for an example). These options should have been used with | |
9 | earlier Stealth versions too, but were overlooked until now (sorry about | |
10 | that). | |
11 | ||
12 | If access to the Unix Domain Socket defined by Stealth running in daemon mode | |
13 | should be restricted, it can be defined in a directory with is only accessible | |
14 | to the user running Stealth (this will often be the root-user). |
0 | Stealth: handles the integrity scan or handles the communication with a | |
1 | running stealth daemon. | |
0 | SyslogStruct: merely a struct containing the values of --syslog* options. It | |
1 | is filled by Options and used by LogUnit | |
2 | 2 | |
3 | Options: singleton, prepares all options received either on the command | |
4 | line or found in the policy file. Ends the program if incompatible | |
5 | options were specified. Initialized by Stealth::Stealth() | |
3 | Msg: m1..m3 insert messages, depending on verbosity level, into imsg, | |
4 | mp writes to cout is used for messages related to parsing the | |
5 | policy file. M1..m3 are global objects, inserting into imsg. | |
6 | The Mstream objects imsg, wmsg and fmsg can also be used, the | |
7 | latter two inserting into cout. | |
8 | ||
9 | Util: Utility class offering members for making directories and | |
10 | determining absolute file names from relative file specifications | |
11 | ||
12 | StealthEnums: an otherwise empty struct, defining the enum Mode and the `Mode | | |
13 | Mode' operator. | |
6 | 14 | |
7 | 15 | PolicyFile: analyzes and stores the information found in the first section of |
8 | the policy file (through its member 'reload'). | |
16 | the policy file (through its member 'reload'). The second section | |
17 | (option specifications) are read by Options::loadPolicyOptions | |
9 | 18 | |
10 | Wait11: implements C++11 (timed) waiting for events, like receiving | |
11 | signals, and sending notifications when they are received. The | |
12 | actual signal handling is handled by the class Stealth itself. | |
13 | ||
14 | IPC: handles the runfile (pid file): requests are written to the | |
15 | runfile followed by signaling the daemon. All actual | |
16 | waiting/notification steps are left to Wait11. signaling the | |
17 | daemon is handled by its member 'signalDaemon' | |
19 | Options: singleton, determines and validates all options received either on | |
20 | the command line or found in the policy file. Ends the program if | |
21 | incompatible options were specified. Initialized by Stealth's | |
22 | constructor. | |
18 | 23 | |
19 | 24 | RunMode: keeps track of the currently active Stealth mode. A mode may also |
20 | 25 | be queried, and the name of a mode can be requested. When a mode |
21 | is changed, setMode is used to update RunMode's mode. | |
26 | is changed, setMode is used to update RunMode's mode. RunMode | |
27 | objects are defined in Stealth, defining d_task for the currently | |
28 | active mode, and d_pending for a requested (next) mode. | |
22 | 29 | |
23 | StealthLog: Handles all logs. d_stealthLog in the Stealth object is a stream | |
24 | into which log messages can be inserted. | |
30 | Report: ostream responsible for inserting information into the REPORT | |
31 | file. The object d_stealthReport is defined by the Stealth object. | |
25 | 32 | |
26 | Msg: m1..m3 insert messages depending on verbosity level. mp is used | |
27 | for messages related to parsing the policy file. These are global | |
28 | objects. Other than the m-objects imsg, wmsg and fmsg can also be | |
29 | used. | |
33 | IntegrityScanner: performs the actual integrity scans. Called from | |
34 | Stealth::integrityScan. Main public interface member: run(). | |
30 | 35 | |
31 | StealthEnums: struct StealthEnums is empty, defining the enum Mode and the | |
32 | Mode | Mode operator. | |
36 | LogUnit: handles all logged messages. Redefinable singleton, with no public | |
37 | members other than LogUnit::init. See REAME.messages for | |
38 | information about the way it operates. | |
33 | 39 | |
40 | Stealth: handles the integrity scan or handles the communication with a | |
41 | running stealth daemon. | |
42 | ||
43 | ||
44 |
0 | Initially the running mode is INTEGRITY_SCAN. Options may change the | |
1 | initial mode. | |
2 | ||
3 | If the --daemon option was not requested, stealth runs as a forgeground | |
4 | process. Unless --repeat is specified there is just one integrity scan after | |
5 | which Stealth::processRequests terminates | |
6 | ||
7 | Flow control is handled through IPC signals, in combination with information | |
8 | written to the pid-file. | |
9 | ||
10 | The first line of the PID file contains the pid of the daemon process. | |
11 | A second line may be written by a stealth process requesting an action of the | |
12 | daemon, followed by the pid of the process issuing the request. Requests are: | |
0 | Stealth may run in one of three modes: | |
1 | ||
2 | 1. Foreground, where stealth performs one integrity scan and terminates; | |
3 | ||
4 | 2. Background, where stealth, after performing its initial integrity scan | |
5 | waits for additional commands and/or performs additional integrity scans | |
6 | after (possibly random) time intervals. | |
7 | ||
8 | 3. IPC, where stealth sends commands to a stealth daemon process. | |
9 | ||
10 | Communication between stealth processes running in modes 2 and 3 is realized | |
11 | through a unix domain socket, which is created by the stealth daemon process. | |
12 | ||
13 | Figure documentation/images/communication.jpg shows the organization: | |
14 | ||
15 | * Stealth --daemon starts the daemon process, its childprocess | |
16 | (stealth/childprocess) starting the ipcInterface thread (separate | |
17 | threads are shown in light green), implemented by the | |
18 | stealth/ipcinterface function. | |
19 | ||
20 | * ChildProcess is the main thread of the running stealth daemon. It | |
21 | performs all the tasks (through stealth/doTasks). | |
22 | ||
23 | DoChores performs some bookkeeping tasks, eventually passing control | |
24 | to stealth/processrequests. | |
25 | ||
26 | JobsHandler runs the current task, which may be an integrity | |
27 | scan. | |
28 | ||
29 | * IpcInterface is a separate thread preparing the next task for | |
30 | jobsHandler. It creates the Unix domain server socket, and waits for | |
31 | incoming request. Incoming requests are verified, and if OK they are | |
32 | forwarded to jobsHandler. IpcInterface's mode of operation is | |
33 | described in more detail below. | |
34 | ||
35 | * Stealth-ipc processes handle ipc requests. These processes connect to | |
36 | the stealth daemon's unix domain socket, passing it the received | |
37 | request. It then waits for a reply from the daemon. If the daemon | |
38 | reports an error the error message is shown, and stealth running in | |
39 | ipc mode terminates with exit value 1. Otherwise exit value 0 is | |
40 | returned and no additional output is shown. | |
41 | ||
42 | Figure documentation/images/ipcinterface.jpg shows the inner workings of | |
43 | the ipcInterface function. | |
44 | ||
45 | * Each cycle of ipcInterface's main loop handles one incoming | |
46 | connection. If a TERMINATE request is received, the ipcInterface | |
47 | thread ends. A TERMINATE request also ends the main (jobsHandler) | |
48 | thread. Once both threads have terminated the stealth daemon ends. | |
49 | ||
50 | * Incoming requests are validated (by Stealth::incomingRequest), and (if | |
51 | valid) initially stored in the local Runmode incoming, processing may | |
52 | be suspended until processRequests is ready to accept the next command | |
53 | (see below at nextTask's description). | |
54 | ||
55 | * Incoming requests are validated. For each possible request a matching | |
56 | ...request function handles the valiadation. If a request cannot be | |
57 | granted (i.e., is invalid), an error message is sent to the | |
58 | stealth-ipc process and another cycle starts. | |
59 | ||
60 | Given a current task (mode of operation) the following requests are | |
61 | valid: | |
62 | ||
63 | ---------------------------------------------------------- | |
64 | Actual Job: Valid Incoming Request: | |
65 | ---------------------------------------------------------- | |
66 | INTEGRITY_SCAN RELOAD, RERUN, SUSPEND, TERMINATE | |
67 | RELOAD TERMINATE | |
68 | SUSPEND RELOAD, RESUME, SUSPEND, TERMINATE | |
69 | ---------------------------------------------------------- | |
70 | ||
71 | Requesting SUSPEND while in SUSPEND mode has no effect (validation | |
72 | returns `nop'): in this case the stealth-ipc process is informed that | |
73 | there is no error but processRequests doesn't actually receive a new | |
74 | command to process | |
75 | ||
76 | * If a request is valid, the incoming request is stored in | |
77 | d_pending. Ongoing jobs may inspect d_pending to see whether they | |
78 | should prematurely stop (e.g., when a TERMINATE request arrives while | |
79 | an integrity scan is being executed, the scan will end after | |
80 | completing the command currently being processed) | |
81 | ||
82 | * Next, ipcInterface waits until jobsHandler is ready for the next task. | |
83 | When ready, notifyTask sets the next task in d_task, and d_pending is | |
84 | reset, after which jobsHandler is notified that it has another task to | |
85 | handle. | |
86 | ||
87 | * The next task may be TERMINATE. If so, ipcInterface ands (and | |
88 | jobsHandler will also end). | |
89 | ||
90 | ||
91 | ||
92 | The Stealth::jobsHandler function handles incoming requests. This function | |
93 | loops until (at the end of the loop) the d_task has been set to TERMINATE. At | |
94 | the top of the loop the next job is determined. Once determined, the | |
95 | requested task starts. | |
96 | ||
97 | Figure documentation/images/nextjob.jpg shows the inner workings of | |
98 | Stealth::nextJob. | |
99 | ||
100 | When returning from nextJob the d_job binary Semaphore has decayed to zero. It | |
101 | is incremented again by ipcInterface once a command is requested by an | |
102 | ipc-stealth process and by some of the task-handling functions (reload, | |
103 | resume, rerun). | |
104 | ||
105 | Since ipcInterface and some of the task-handling functions may set the next | |
106 | command to process, the permission to set the next command is set by the d_ipc | |
107 | semaphore. Once ipcInterface returns from d_ipc.wait() d_ipc blocks until it | |
108 | is incremented by d_ipc.notify(). Initially d_ipc blocks, but it is | |
109 | incremented by startScan and suspend. | |
110 | ||
111 | When nextJob returns the next task has been set. This is realized as follows: | |
112 | ||
113 | * If at daemon startup --repeat was not specified then nextJob simply | |
114 | waits for a command which is received from an ipc-stealth process through | |
115 | ipcInterface (alternatively, the command may be set by the mentioned | |
116 | request-processing functions). | |
117 | ||
118 | * time-limited wait: otherwise, nextJobs waits until either a command was | |
119 | set (as with the plain wait), or until a (random) delay has passed. | |
120 | ||
121 | * If no timeout occurred, then a command was specified and nextJob | |
122 | returns with the next command. | |
123 | ||
124 | * Otherwise, in suspend mode or while an integrity scan is still active, | |
125 | nextJob loops back to the time-limited wait step. | |
126 | ||
127 | * Otherwise, --repeat was specified, and the waiting time has passed, so | |
128 | the next task automatically becomes INTEGRITY_SCAN (and nextJob | |
129 | returns) | |
130 | ||
131 | ||
132 | Integrity scans are performed by Stealth::integrityScan. | |
133 | ||
134 | ||
135 | ||
136 | ||
137 | ||
138 | Flow control is handled by communicating through a Unix Domain Socket, which | |
139 | uses the run-file. Requests are: | |
13 | 140 | |
14 | 141 | suspend, |
15 | 142 | resume, |
19 | 146 | and perform another integrity scan. |
20 | 147 | terminate |
21 | 148 | |
22 | A request is written to the PID file, followed by sending the daemon a SIGUSR1 | |
23 | signal. When the daemon has completed the request it sends the requesting | |
24 | process a SIGUSR1 signal; | |
149 | Requests are received through the Unix domain socket defined by the run-file | |
150 | the daemon performs the request and replies with an answer indicating | |
151 | success or failure. Success is inferred when an empty line is received. | |
152 | Failure information contains an indication of the nature of the failure. | |
153 | ||
154 | Requests are passed to the daemon from the function Stealth::contactPeer. | |
155 | ||
156 | | - the pid file is locked | |
157 | | - the request is written to the pid-file | |
158 | | - the pid file is unlocked. | |
159 | | | |
160 | | A request is written to the PID file, followed by sending the daemon a SIGUSR1 | |
161 | | signal. When the daemon has completed the request it sends the requesting | |
162 | | process a SIGUSR1 signal; | |
25 | 163 | |
26 | 164 | |
27 | 165 | Stealth uses a RunMode object to keep track of its current mode of operation |
28 | and an IPC object to handle the inter process communication. | |
166 | | now OBS? and an IPC object to handle the inter process communication. | |
167 | ||
168 | The member Stealth::policyMode handles the actual commands. | |
169 | ||
170 | policyMode: | |
171 | ============== | |
172 | policyMode forks if a Stealth should run as a daemon, in which case the | |
173 | fork's child process performs the daemon's tasks, and the parent process | |
174 | immediately finishes. | |
175 | ||
176 | When a daemon starts its childProcess prepares the daemon (using | |
177 | Fork::prepareDaemon), and the communication thread starts, defining the | |
178 | unix domain server socket. Hereafter 'doTasks' starts. | |
179 | ||
180 | communicator: | |
181 | ============= | |
182 | ||
183 | The communicator creates the LocalServerSocket, and loops while d_run.mode() | |
184 | is unequal TERMINATE. When a request arrives, the matching function is | |
185 | called. These functions should return an empty string indicating that the | |
186 | request can be handled. Otherwise the returned string contains an error | |
187 | message which is returned to the requestor. | |
188 | ||
189 | If the request can be handled d_chore is notified, and the communicator waits | |
190 | for d_communicate to return, indicating that the request has been | |
191 | handled. When d_communicate.wait() returns the contents of d_result is | |
192 | returned to the requestor. Again: an empty string indicates that the request | |
193 | was successfully processed. | |
194 | ||
195 | doTasks: | |
196 | ========= | |
197 | ||
198 | With foreground runs 'doTasks' is directly started. | |
29 | 199 | |
30 | 200 | The flow of control handling requests is defined in processRequests, |
31 | called from doChores. ProcessRequests defines a loop basically processing a | |
201 | called from doTasks. ProcessRequests defines a loop basically processing a | |
32 | 202 | request and waiting for the next request ((waitForRequest) |
33 | 203 | |
34 | 204 | The file integrity scan itself is handled by an IntegrityScanner object. |
35 | 205 | |
36 | ||
37 | Communications with the daemon use the run-file and signals SIGUSR1 (and | |
38 | SIGTERM). The run-file by default contains the pid of the daemon process. The | |
39 | signalling stealth process adds a request to the | |
40 | file. The daemon reads the request and honors it if possible. | |
206 | | | |
207 | | Communications with the daemon use the run-file and signals SIGUSR1 (and | |
208 | | SIGTERM). The run-file by default contains the pid of the daemon process. The | |
209 | | signalling stealth process adds a request to the | |
210 | | file. The daemon reads the request and honors it if possible. | |
211 | ||
212 | ||
213 | processRequests: | |
214 | ================ | |
215 | ||
216 | Stealth (when performing integrity scans) starts up with an initial mode | |
217 | INTEGRITY_SCAN. At processRequests netTask() returns the next mode, which is | |
218 | then processed by 'process'. | |
219 | ||
220 | NextTask() inspects the current mode. If it's WAIT wait() is called, which | |
221 | ||
222 | ||
223 | ||
224 | Possible task requests: | |
225 | ======================= | |
226 | rerun: OK in mode WAIT | |
227 | suspend: OK in mode SCAN, WAIT, SUSPEND | |
228 | resume: OK in mode SUSPEND | |
229 | reload: OK in mode SCAN, WAIT, SUSPEND | |
230 | terminate: always OK. | |
231 | ||
232 |
0 | Messages sent to m1, m2, and m3 (see ../msg) are sent to imsg. | |
1 | ||
2 | LogUnit::setupLogs() creates an FBB::Log and FBB::SyslogSteam if requested so | |
3 | by options. | |
4 | ||
5 | It adds these files to an FBB::MultiStreambuf, and (if requested by --stdout) | |
6 | also adds cout. | |
7 | ||
8 | If any streams are stored, the MultiStreambuf is installed in imsg. Following | |
9 | this, all messages inserted into imsg are sent to the requested log streams. | |
10 | ||
11 | Fatal messages, sent to fmsg, are handled similarly: | |
12 | ||
13 | A MultiStreambuf receives imsg, and optionally (when calling setupLogs(ostream | |
14 | &report)) into the ostream which inserts messages into the Report object. | |
15 | ||
16 | The stream received by setupLogs is itself a wrapper around the actual Report | |
17 | object, and its streambuf is defined in stealth/stealth.ih: all text inserted | |
18 | into fmsg is also sent to this wrapper ostream, which forwards its characters | |
19 | to its streambuffer's overflow member. This member sends all its characters to | |
20 | Stealth's d_report object. When the wrapper stream is flushed, it calls | |
21 | d_report.mail(), to process d_report's info by mail. | |
22 | ||
23 | LogUnit: | |
24 | ======== | |
25 | ||
26 | SyslogStream --+ | |
27 | | | |
28 | Log --+--> MultiStreambuf | |
29 | | | | |
30 | cout (with --stdout) --+ | | |
31 | | | |
32 | | | |
33 | v | |
34 | imsg.reset(...) | |
35 | | | |
36 | +----------+----------+ | |
37 | m1 m2 m3 | |
38 | ||
39 | ||
40 | imsg ----+ | |
41 | | | |
42 | +--> MultiStreambuf | |
43 | | | | |
44 | report ----+ | | |
45 | | | |
46 | v | |
47 | fmsg.reset(...) | |
48 | ||
49 | ||
50 | ||
51 |
0 | 0 | #define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)"; |
1 | #define VERSION "3.00.00" | |
2 | #define YEARS "2005-2014" | |
1 | #define VERSION "4.00.00" | |
2 | #define YEARS "2005-2015" |
0 | #!/usr/bin/icmake -qt/tmp/bisonc++ | |
0 | #!/usr/bin/icmake -qt/tmp/stealth | |
1 | 1 | |
2 | 2 | #include "icmconf" |
3 | 3 | |
50 | 50 | if (argv[2] == "strip") |
51 | 51 | strip = "strip"; |
52 | 52 | |
53 | if (option == "p") | |
54 | { | |
55 | system("tput clear"); | |
56 | system("icmbuild program strip"); | |
57 | exit(0); | |
58 | } | |
59 | ||
53 | 60 | if (option == "program") |
54 | 61 | { |
55 | 62 | system("icmbuild program " + strip); |
63 | 70 | exit(0); |
64 | 71 | } |
65 | 72 | |
66 | printf("Usage: build [-p] what\n" | |
73 | printf("Usage: build what\n" | |
67 | 74 | "Where `what' is one of:\n" |
68 | 75 | " clean - clean up remnants of previous " |
69 | 76 | "compilations\n" |
71 | 78 | " library - build " PROJECT "'s library\n" |
72 | 79 | " man - build the man-page (requires Yodl)\n" |
73 | 80 | " manual - build the manual (requires Yodl)\n" |
81 | " p - build " PROJECT " after `tput clear' and\n" | |
82 | " strip the executable)\n" | |
74 | 83 | " program [strip] - build " PROJECT " (optionally strip the\n" |
75 | 84 | " executable)\n" |
76 | 85 | " oxref [strip] - same a `program', also builds xref file\n" |
0 | stealth (4.00.00) | |
1 | ||
2 | * Stealth 4.00.00 uses Unix Domain Sockets instead of signals to | |
3 | communicatie with the stealth monitor running as a daemon. | |
4 | ||
5 | * Previously required absolute file paths are no longer required. When | |
6 | relative file paths are used with the Stealth daemon or with Stealth doing | |
7 | an integrity scan as foreground process they are interpreted relatively to | |
8 | the current working directory, or (when specified in the policy file) | |
9 | relative to the USE BASE location. With Stealth running in IPC mode | |
10 | relative file paths are interpreted relative to the directory in which | |
11 | Stealth running in IPC mode was started. | |
12 | ||
13 | * A README.flow file is provided with several separately provided | |
14 | illustrative images in the directory documentation/images. Similarly: | |
15 | README.messages describes the organization of log/mail message handling. | |
16 | ||
17 | * Specifications for the logrotate specifications should use 'copytruncate' | |
18 | and 'sharedscripts' (see the man-page for an example). | |
19 | ||
20 | * share/usr/bin/stealthcron now specifies a Unix Domain Socket (usage not | |
21 | changed). | |
22 | ||
23 | * Fixed compilation errors that emerged with g++-5, reported by Matthias | |
24 | Klose. | |
25 | ||
26 | -- Frank B. Brokken <f.b.brokken@rug.nl> Sat, 07 Feb 2015 21:14:30 +0100 | |
27 | ||
0 | 28 | stealth (3.00.00) |
1 | 29 | |
2 | 30 | * Version 3.00.00 completely reorganizes and refactors Stealth's |
Binary diff not shown
Binary diff not shown
Binary diff not shown
13 | 13 | manpagename(stealth)(Stealthy File Integrity Scanner) |
14 | 14 | |
15 | 15 | manpagesynopsis() |
16 | s() --daemon pidfile --dry-run --log <path> --logmail+nl() | |
16 | `<uds>' represents the location of the used Unix Domain Socket.nl() | |
17 | ||
18 | s() --daemon <uds> --dry-run --log <file-spec> --logmail+nl() | |
17 | 19 | --max-size <size>[BKMG] --no-mail --parse-policy-file+nl() |
18 | 20 | --random-interval <seconds> --repeat <seconds>nl() |
19 | --run-command <nr> --skip-files <path> --stdout --syslog+nl() | |
21 | --skip-files <file-spec> --syslog+nl() | |
20 | 22 | --syslog-facility <fac> --syslog-priority <pri> |
21 | 23 | --syslog-tag <tag>nl() |
22 | 24 | --verbosity <value> policy |
23 | 25 | |
24 | s() {--reload,--rerun,--resume,--suspend,--terminate} pidfile | |
26 | s() --dry-run --log <file-spec> --logmail+nl() | |
27 | --max-size <size>[BKMG] --no-mail --parse-policy-file+nl() | |
28 | --random-interval <seconds> --repeat <seconds>nl() | |
29 | --run-command <nr> --skip-files <file-spec> --stdout --syslog+nl() | |
30 | --syslog-facility <fac> --syslog-priority <pri> | |
31 | --syslog-tag <tag>nl() | |
32 | --verbosity <value> policy | |
33 | ||
34 | s() {--reload,--rerun,--resume,--suspend,--terminate} <uds> | |
25 | 35 | |
26 | 36 | s() --help --version |
27 | 37 | |
32 | 42 | quote( |
33 | 43 | bf(SSH-based Trust Enforcement Acquired through a Locally Trusted Host.) |
34 | 44 | ) |
35 | s() is based on an idea by em(Hans Gankema) and em(Kees Visser), both at | |
45 | S() is based on an idea by em(Hans Gankema) and em(Kees Visser), both at | |
36 | 46 | the Center for Information Technology of the University of Groningen. em(Hopko |
37 | 47 | Meijering) provided valuable suggestions for improvement. |
38 | 48 | |
39 | s()'s main task is to perform file integrity tests. However, the | |
49 | S()'s main task is to perform file integrity tests. However, the | |
40 | 50 | testing itself will leave no sediments on the tested computer. Therefore, |
41 | 51 | s() has em(stealthy) characteristics. This is considered an |
42 | 52 | important feature, improving the security (integrity) of the software of |
43 | 53 | computers monitored by s(). |
44 | 54 | |
45 | On the other hand, one should realize that s() intends to be just another | |
46 | security tool: other security measures like firewalls, portscanners, intrusion | |
47 | detection systems, dropping unencrypted protocols, etc. are usually required | |
48 | to improve or promote the security of a group of computers that are connected | |
49 | to the Internet. | |
50 | ||
51 | s() uses a policy file to determine the actions to perform. Each | |
52 | policy file is uniquely associated with a host to be tested. This host | |
55 | Please realize that s() intends to be just another security tool: other | |
56 | security measures like firewalls, portscanners, intrusion detection systems, | |
57 | dropping unencrypted protocols, etc. are usually required to improve the | |
58 | security of a group of computers that are connected to the Internet. S() is a | |
59 | file integrity scanner, and file integrity scanners offer no substitute for | |
60 | those tools (and vv.). | |
61 | ||
62 | S() uses a policy file to determine the actions to perform. Each | |
63 | policy file is uniquely associated with a host being monitored. This host | |
53 | 64 | (called the em(client) below) trusts the computer on which s() runs, called |
54 | the em(controller) (hence: a em(Locally Trusted Host)). The controller | |
65 | the em(monitor) (hence: a em(Locally Trusted Host)). The monitor | |
55 | 66 | performs tasks (normally file integrity tests) that em(Enforce) the em(Trust) |
56 | 67 | we have in the client computer. Since almost all integrity tests can be run |
57 | on the client, one controller can control many clients, even if the | |
58 | controller itself uses aged hard- and software components. | |
59 | ||
60 | As the controller and the client normally are different computers, the | |
61 | controller must communicate with the client in a secure fashion. This is | |
62 | realized using SSH. So, there's another element of `local trust' involved | |
63 | here: the client should permit the controller to set up a secure SSH | |
64 | connection allowing the controller to access sensitive files and private parts | |
65 | of the client's file system. | |
66 | ||
67 | bf(It is important to ensure that there is no public access to the | |
68 | controller. All inbound services should be denied. The only access to | |
69 | the controller should be via its console and the controller should be placed | |
70 | in a physically secure location. Sensitive information of clients are stored | |
71 | in the controller, and passwordless access to clients can be obtained from the | |
72 | controller by anyone who gains (root)-access). | |
73 | ||
74 | The controller itself normally only uses two kinds of outgoing services: | |
68 | on the client, one monitor can control many clients, even if the | |
69 | monitor itself uses aged hard- and software components. | |
70 | ||
71 | As the monitor and the client are (i.e., should be) different computers, the | |
72 | monitor must communicate with the client in a secure fashion. This is realized | |
73 | through SSH. So, there's another element of `local trust' involved here: the | |
74 | client should permit the monitor to set up a secure SSH connection allowing | |
75 | the monitor to access sensitive elements in the client's file system. | |
76 | ||
77 | bf(It is important to ensure that public access to the monitor is | |
78 | prevented. No incoming services should be allowed. The only access to the | |
79 | monitor should be via its console and the monitor should be placed in a | |
80 | physically secure location. Sensitive information of clients are stored in the | |
81 | monitor's file system. To access the clients s() in daemon mode can use a | |
82 | passphrase-protected ssh-key, allowing s() to perform its tasks | |
83 | thereafter. This, too, makes it important to prevent the monitor from being | |
84 | accessed by unauthorized persons.) | |
85 | ||
86 | If, instead of running s() in deamon mode it is preferred to let s() perform | |
87 | single, but automated integrity scans, then new bf(ssh)(1) connections may be | |
88 | difficult to establish if the used ssh-key is passphrase-protected. To | |
89 | implement this scenario (i.e., automated integrity scans using passphrase | |
90 | protected ssh-keys) the program bf(ssh-cron)(1) can profitably be used. | |
91 | ||
92 | S()'s current way of connecting to clients uses a single bf(ssh)(1) | |
93 | connection, which results in only a single bf(sshd)(1) | |
94 | entry in the client's logfiles, which lasts for the duration of s()'s | |
95 | run. When using s() in daemon mode this too minimizes the `footprint' s() has | |
96 | on the client hosts. | |
97 | ||
98 | The monitor itself normally only requires two types of outgoing services: | |
75 | 99 | bf(SSH) to reach its clients, and some mail transport agent (e.g., |
76 | 100 | bf(sendmail)(1)) to forward its outgoing mail to some mail-hub. |
77 | 101 | |
78 | Here is what happens when s() is run using the first synopsis: | |
102 | Here is what happens when s() running using the first synopsis: | |
79 | 103 | itemization( |
80 | it() First, the em(policy) file is read. This determines the actions to be | |
81 | performed, and the values of several variables that are used by s(). | |
82 | ||
83 | it() If the command-line option tt(--daemon pidfile) is specified, s() | |
84 | runs as a backgrond process, writing its process id in the file tt(pifile). | |
85 | ||
86 | With tt(--repeat <seconds>) the scan is rerun every tt(<seconds>) seconds. The | |
87 | number of seconds until the next rerun is restricted by s() to a value of at | |
88 | least 60. However, using the tt(--rerun pidfile) option a daemon s() another | |
89 | integrity scan can be requested after a shorter interval. | |
90 | ||
91 | When tt(--daemon) is specified the scan is performed just once, whereafter | |
92 | s() waits until another integrity scan is requested using the | |
93 | s() tt(--rerun pidfile) invokation | |
94 | ||
95 | it() Next, the controller opens a command shell on the client using | |
96 | bf(ssh)(1), and a command shell on itself using bf(sh)(1). | |
104 | it() First, the em(policy) file is read. For each client a policy file is | |
105 | defined, specifying the actions to be performed, and specifying the values of | |
106 | several variables used by s(). | |
107 | ||
108 | it() If the command-line option tt(--daemon <uds>) is specified, s() | |
109 | runs as a daemon process, using the Unix Domain Socket (tt(<uds>)) for | |
110 | communication with s() processes running in IPC mode. | |
111 | ||
112 | If access to the Unix Domain Socket defined by Stealth running in daemon mode | |
113 | should be restricted, it can be defined in a directory with is only accessible | |
114 | to the user running Stealth (this will often be the root-user). | |
115 | ||
116 | When running in daemon mode, tt(--repeat <seconds>) may be specified to rerun | |
117 | the integrity scan every tt(<seconds>) seconds. If an integrity scan is being | |
118 | performed when, according to the repeat interval the next integrity scan is | |
119 | due, then the current scan is first completed. Once completed, the next | |
120 | integrity scan will be performed after tt(seconds) seconds. | |
121 | ||
122 | it() Next, the monitor opens a command shell on the client using | |
123 | bf(ssh)(1), and a command shell on the monitor computer itself using | |
124 | bf(sh)(1). | |
97 | 125 | |
98 | 126 | it() Once the command shells are available, commands defined in the policy |
99 | 127 | file are executed in their order of appearance. Examples are given |
100 | 128 | below. Normally, return values of the programs are tested. When return values |
101 | are tested s() terminates when a non-zero return | |
102 | value is received. If this happens, a message stating the | |
103 | reason why s() terminated is written to the report file (and into the mail | |
104 | message sent by s()). In some cases (e.g., when the report file could not be | |
105 | written), the message is written to the standard error stream. | |
106 | ||
107 | it() In most cases, integrity tests can be controlled using the | |
108 | bf(find)(1) program, calling programs like bf(ls)(1), bf(sha1sum)(1) or its | |
109 | own tt(-printf) method to produce file-integrity related statistics. Most of | |
110 | these programs write file names at the end of generated lines. This | |
111 | characteristic is used by an internal routine of s() to detect changes in the | |
112 | generated output, which could indicate some harmful intent, like an installed | |
113 | em(root-kit). | |
129 | are to be tested s() terminates when a non-zero return value is sensed. If | |
130 | this happens, a message stating the reason why s() terminated is written to | |
131 | the report file (and into the mail sent by s()). In some cases (e.g., when the | |
132 | report file could not be written), the message is written to the standard | |
133 | error stream. | |
134 | ||
135 | it() Very often integrity tests can be controlled using bf(find)(1), | |
136 | calling programs like bf(ls)(1), bf(sha256sum)(1) or its own tt(-printf) | |
137 | method to produce file-integrity related statistics. Most of these programs | |
138 | write file names at the end of generated lines. This characteristic is used by | |
139 | one of s()'s internal routines to detect changes in the generated output. Such | |
140 | changes could indicate some harmful intent, like an installed em(root-kit). | |
114 | 141 | |
115 | 142 | it() When changes are detected, they are logged in a em(report file), to |
116 | 143 | which information is always appended. S() never reduces the report file's size |
117 | or rewrites its contents. Whenever information is added to the report file | |
118 | (exceeding a plain time stamp) the appended information is e-mailed to a | |
119 | configurable e-mail address for further (human) processing. Usually the e-mail | |
120 | is sent to the systems manager of the tested client. S() follows the `dark | |
121 | cockpit' approach in the sense that no mail is sent when no changes were | |
122 | detected. | |
123 | ||
124 | it() When the tt(--repeat) or tt(--rerun) options are issued, the report | |
125 | file should not be rotated by, e.g., a log-rotating process, but the report | |
126 | file may safely be rotated between a pair of tt(--suppress) and tt(--resume) | |
127 | commands. | |
128 | ) | |
129 | ||
130 | manpagesection(REPORT FILE ROTATION) | |
131 | Since s() only appends information to the report file, the report file's | |
132 | size may eventually become prohibitively large, and log-rotation may be | |
133 | desirable. It is of course possible to issue a tt(--terminate) command, rotate | |
134 | the logfiles, and restart s(), but s() also offers a facility to temporarily | |
135 | suspend integrity scans performed by a s() daemon process: | |
136 | itemization( | |
137 | it() Calling s() with the option tt(--suspend <pidfile>) suspends the | |
138 | daemon's integrity scans. If s() is | |
139 | actually performing a series of integrity scans when | |
140 | tt(--suspend) is issued, the currently executing command is first | |
141 | completed after which the tt(--suspend) command completes. Once | |
142 | the s() daemon has been suspended, automatic or explicit | |
143 | integrity scan requests are denied, and the daemon can only be | |
144 | instructed to resume its scanning tasks (s() --resume <pidfile>) | |
145 | or to terminate (s() --terminate <pidfile>). | |
146 | ||
147 | it() Once `s() tt(--suspend <pidfile>)' has returned, the report file | |
148 | may safely be rotated (using, e.g., bf(logrotate)(1)), and a new | |
149 | (empty) report file may optionally be created by the logrotation | |
150 | process. | |
151 | ||
152 | it() Once the log-rotation has been completed, the log-rotation process | |
153 | should issue the command `s() tt(--resume <pidfile>)'. This | |
154 | resumes the activities of a suspended s() daemon process, | |
155 | immediately performing the next integrity scan. Following this the | |
156 | s() daemon is back to its original integrity scanning mode. | |
157 | ) | |
158 | Here is an example of bf(logrotate)(1) specification rotating s() | |
159 | log-files: | |
160 | verb(/root/stealth/host/report { | |
161 | weekly | |
162 | rotate 12 | |
163 | compress | |
164 | missingok | |
165 | prerotate | |
166 | /usr/bin/stealth --suppress /run/stealth.host | |
167 | endscript | |
168 | postrotate | |
169 | /usr/bin/stealth --resume /run/stealth.host | |
170 | endscript | |
171 | }) | |
172 | ||
173 | manpagesection(RELOAD, RERUN AND TERMINATE) | |
174 | ||
175 | Here is what happens when s() is run using the second synopsis: | |
176 | itemization( | |
177 | it() When started as s() tt(--reload <pidfile>), the s() daemon process | |
178 | reloads its policy file and (if specified) tt(--skip-files) | |
179 | specification file. Next the s() daemon process performs a file | |
180 | integrity scan using the information in the re-read policy and | |
181 | skip-files files. S() can reload the (modified) contents of the | |
182 | originally specified policy- and skip-files names. If another policy | |
183 | and/or skip-files files must be used another s() process must be | |
184 | started, for which these new filenames are specified. | |
185 | ||
186 | it() When started as s() tt(--rerun <pidfile>), the s() daemon performs | |
187 | another scan (unless it has been suspended using s() tt(--suspend | |
188 | <pidfile>)). | |
189 | ||
190 | it() When started as s() tt(--terminate pidfile), the s() daemon is | |
191 | terminated. | |
192 | ) | |
193 | ||
194 | manpagesection(OPEN SSH LINK TO CLIENTS) | |
195 | ||
196 | Once s() is started as a foreground or daemon process performing file | |
197 | integrity scans one one bf(ssh)(1) connection is opened to the client. This | |
198 | connection remains active during s()'s lifetime to minimize the number of | |
199 | bf(sshd) entries caused by s() in the client's log files. | |
144 | or rewrites its contents. When information is added to the report file (beyond | |
145 | a plain time stamp) the newly added information is e-mailed to a configurable | |
146 | e-mail address for further (human) processing. Usually the e-mail is sent to | |
147 | the systems manager of the tested client. S() follows the `dark cockpit' | |
148 | approach in the sense that no mail is sent when no changes were detected. | |
149 | ||
150 | it() Report and other log-files may safely be rotated between a pair of | |
151 | tt(--suppress) and tt(--resume) commands (see below at the section `REPORT | |
152 | FILE ROTATION'). | |
153 | ) | |
154 | ||
155 | If s() should not be run as a daemon process the second synopsis can be | |
156 | used. In this case s() performs one or more integrity scans (the latter when | |
157 | the tt(--repreat) option was specified). When a single integrity scan is | |
158 | requested s() terminates after the scan. When tt(--repeat) is specified s() | |
159 | shows a prompt (i.e., `tt(? )') and terminates after pressing the | |
160 | tt(Enter)-key. | |
161 | ||
162 | The third synopsys is used for communication with a s() daemon. In this case | |
163 | the the Unix Domain Socket defined by the s() daemon process must be | |
164 | specified after the option specifying the requested command. | |
165 | ||
166 | manpagesection(OPTIONS) | |
167 | ||
168 | includefile(../manual/running/options.yo) | |
169 | ||
170 | manpagesection(OPEN SSH LINK TO CLIENTS) | |
171 | ||
172 | Once s() has started as a foreground or daemon process performing file | |
173 | integrity scans bf(ssh)(1) is used to connect to the client(s) | |
174 | monitored by s(). While s() runs only one bf(ssh)(1) connection is opened to | |
175 | each client. This connection remains active during s()'s lifetime to minimize | |
176 | the number of bf(sshd) entries in the client's log files. | |
200 | 177 | |
201 | 178 | nsect(THE POLICY FILE) |
202 | 179 | |
207 | 184 | directives) (starting with the keyword bf(USE)) and em(commands). Blank lines |
208 | 185 | and information beyond hash-marks (#) are ignored, while lines following lines |
209 | 186 | terminating in backslashes (\) are concatenated (em(en passant) removing these |
210 | trailing backslashes). Initial white space on lines of the policy file is | |
187 | trailing backslashes). Leading white space on lines of the policy file is | |
211 | 188 | ignored. |
212 | 189 | |
213 | 190 | The (optional) second section starts at a line merely containing |
214 | tt(%%). Following this separating line long option specifications can be | |
215 | entered (see below at section bf(OPTIONS)). | |
191 | tt(%%). Following this separating line several long option specifications can | |
192 | be entered (see below at section bf(OPTIONS)). Options specified on the | |
193 | command-line take priority over options specified in the policy file. Although | |
194 | the tt(--reload) option reloads the policy file, it will not change option | |
195 | values originally specified as command-line options. This section may contain | |
196 | specifications of the tt(skip-files) and tt(log) options. Relative file | |
197 | locations specified for these options are interpreted relative to the location | |
198 | of the policy file. E.g., if the policy file argument is specified as | |
199 | tt(/root/client/policy) then the specification tt(log: client.log) results in | |
200 | s() writing its logs into the file tt(/root/client/client.log). | |
201 | ||
216 | 202 | |
217 | 203 | nsect(DEFINE DIRECTIVES) |
218 | 204 | |
219 | 205 | bf(DEFINE) directives are used to associate longer strings of text with |
220 | 206 | certain symbols. E.g., after |
221 | tt(DEFINE FINDARGS -xdev -type f -exec /usr/bin/sha1sum {} \;) | |
207 | tt(DEFINE FINDARGS -xdev -type f -exec /usr/bin/sha256sum {} \;) | |
222 | 208 | the specification tt(${FINDARGS}) may be used in bf(USE DIRECTIVES) and |
223 | 209 | bf(commands) (see below) to use the text associated with the bf(FINDARGS) |
224 | 210 | symbol. |
234 | 220 | preserved). Specifications in angular brackets (like tt(<this>)) represent |
235 | 221 | specifications to be provided by s()'s users: |
236 | 222 | itemization( |
237 | it() bf(USE BASE) tt(<base-irectory>)nl() | |
223 | it() bf(USE BASE) tt(<base-directory>)nl() | |
238 | 224 | bf(BASE) defines the directory from where s() operates. All subsequent |
239 | relative path specifications are interpreted relative to bf(BASE). em(By | |
240 | default) this is the directory where s() was started. nl() | |
225 | relative path specifications in the policy file (including relative path | |
226 | specifications in the policy's second part) are interpreted relative to | |
227 | bf(BASE). em(By default) this is the directory where s() was started. nl() | |
241 | 228 | bf(BASE) and other non-existing paths are created automatically by |
242 | 229 | s() if not yet existing.nl() |
243 | 230 | Example:nl() |
246 | 233 | it() bf(USE DD) tt(<dd>)nl() |
247 | 234 | The bf(DD) specification uses tt(/bin/dd) as default, and defines the |
248 | 235 | location of the bf(dd)(1) program, both on the server and on the client. The |
249 | bf(DD) program is used to copy files between the client and the controller | |
236 | bf(DD) program is used to copy files between the client and the monitor | |
250 | 237 | over the existing ssh-connection. The program specified here is only used by |
251 | 238 | s() when executing tt(PUT) and tt(GET) commands (described below).nl() |
252 | 239 | Example showing the default:nl() |
254 | 241 | |
255 | 242 | it() bf(USE DIFF) tt(<diff>)nl() |
256 | 243 | The default bf(DIFF) specification uses tt(/usr/bin/diff), |
257 | and defines the location of the bf(diff)(1) program on the controller. The | |
244 | and defines the location of the bf(diff)(1) program on the monitor. The | |
258 | 245 | bf(diff)(1) program is used to compare a formerly created logfile of an |
259 | 246 | integrity check with a newly created logfile.nl() |
260 | 247 | Example showing the default:nl() |
274 | 261 | report of the integrity scan of the client. The `dark cockpit' philosophy is |
275 | 262 | followed here: mail is only sent when a modification is detected.nl() |
276 | 263 | Example showing the default (apparently an email address on the |
277 | controller):nl() | |
264 | monitor):nl() | |
278 | 265 | tt(USE EMAIL root) |
279 | 266 | |
280 | 267 | it() bf(USE MAILER) tt(<mailer>)nl() |
307 | 294 | quote in a string that itself is delimted by double quotes; use tt(\') to use |
308 | 295 | a single quote in a string that itself is delimted by single quotes. |
309 | 296 | |
310 | it() bf(USE REPORT) tt(<reportfile>)nl() | |
297 | it() bf(USE REPORT) tt(<file-spec>)nl() | |
311 | 298 | bf(REPORT) defines the name of the reportfile. Information is always |
312 | 299 | appended to this file. At each s() integrity scan a em(time marker line) is |
313 | 300 | written to the report file. Only when (in addition to the marker line) |
314 | 301 | additional information is appended to the report file the added contents of |
315 | 302 | the report file are mailed to the mail address specified in the bf(USE EMAIL) |
316 | specification.nl() | |
303 | specification. When a relative file specification is used it is interpreted a | |
304 | location relative to the tt(USE BASE) specification.nl() | |
317 | 305 | Example showing the default:nl() |
318 | 306 | tt(USE REPORT report) |
319 | 307 | |
320 | 308 | it() bf(USE SH) tt(<sh>)nl() |
321 | 309 | The bf(SH) specification uses tt(/bin/sh) as default, and defines the |
322 | command shell used by the controller to execute commands on itself.nl() | |
310 | command shell used by the monitor to execute commands on itself. This must be | |
311 | an absolute path specification.nl() | |
323 | 312 | Example showing the default:nl() |
324 | 313 | tt(USE SH /bin/sh) |
325 | 314 | |
326 | 315 | it() bf(USE SSH) tt(<user>)nl() |
327 | 316 | bf(The SSH specification has no default), and em(must) be |
328 | specified. Assuming the client em(trusts) the controller (which is, after all, | |
329 | what this program is all about; so this should not be a very strong | |
330 | assumption), preferably the public ssh-identity key of the controller should | |
331 | be placed in the client's root tt(.ssh/authorized_keys) file, granting the | |
332 | controller root access to the client. Root access is normally needed to gain | |
333 | access to all directories and files of the client's file system. | |
334 | ||
335 | In practice, connecting to a account using the bf(sh)(1) shell is | |
317 | specified. This must be an absolute path specification. | |
318 | ||
319 | Assuming the client em(trusts) the monitor (which is after all what this | |
320 | program is all about, so this should not be a very strong assumption), | |
321 | preferably the public ssh key of the monitor should be placed in the | |
322 | client's root tt(.ssh/authorized_keys) file, granting the monitor root access | |
323 | to the client. Root access is normally needed to gain access to all | |
324 | directories and files of the client's file system. | |
325 | ||
326 | In practice, connecting to an account using the bf(sh)(1) shell is | |
336 | 327 | preferred. When another shell is already used by that account, one should make |
337 | sure that that shell doesn't define its own redirections for standard input | |
328 | sure that its shell doesn't define its own redirections for standard input | |
338 | 329 | and standard output. One way to accomplish that is for force the execution of |
339 | 330 | tt(/bin/sh) in the bf(USE SSH) specification. |
340 | 331 | Examples: |
341 | 332 | verb( # root's shell is /bin/sh: |
342 | 333 | USE SSH root@client -T -q |
343 | # root uses another shell | |
334 | # root uses another shell, but the use of /bin/bash is forced: | |
344 | 335 | USE SSH root@client -T -q exec /bin/bash |
345 | 336 | # an alternative: |
346 | 337 | USE SSH root@client -T -q exec /bin/bash --noprofile) |
347 | 338 | ) |
348 | 339 | |
349 | In some installations s() is used to inspect the computer itself, even | |
350 | though this is em(not) recommended, as it breaks one of the main reasons | |
351 | for s()'s existence. In situations where s() is used to monitor the integrity | |
352 | of the tt(localhost), tt(/bin/bash) could be specified with the tt(USE SSH) | |
353 | directive. For example: | |
340 | In some installations s() is used to inspect the monitor itself, even | |
341 | though this is em(not) recommended, as it breaks one of the main reasons for | |
342 | s()'s existence. But in those situations (so, where s() is used to monitor the | |
343 | integrity of the tt(localhost)), tt(/bin/bash) could be specified at the | |
344 | tt(USE SSH) directive. For example: | |
354 | 345 | verb( # For stealth inspecting localhost: |
355 | 346 | USE SSH /bin/bash --noprofile) |
356 | 347 | |
379 | 370 | Example:nl() |
380 | 371 | tt(LABEL Inspecting files in /etc\nIncluding subdirectories)nl() |
381 | 372 | tt(LABEL) nl() |
382 | (In this example the latter bf(LABEL) specification erases the former | |
383 | label text). | |
373 | (In this example the former bf(LABEL) specification is erased by the | |
374 | latter bf(LABEL) command). | |
384 | 375 | ) |
385 | 376 | |
386 | 377 | nsect(LOCAL COMMANDS) |
387 | 378 | |
388 | bf(LOCAL) commands are executed on the controller itself: | |
379 | bf(LOCAL) commands are executed on the monitor itself: | |
389 | 380 | itemization( |
390 | 381 | it() bf(LOCAL) tt(<command>)nl() |
391 | Execute tt(command) on the controller, using the bf(SH) command | |
382 | Execute tt(command) on the monitor, using the bf(SH) command | |
392 | 383 | shell. The command must succeed (i.e., must return a zero exit value). nl() |
393 | 384 | Example:nl() |
394 | tt(LOCAL scp rootsh@client:/usr/bin/sha1sum /tmp)nl() | |
395 | This command copies the client's bf(sha1sum)(1) program to the | |
396 | controller. | |
385 | tt(LOCAL scp rootsh@client:/usr/bin/sha256sum /tmp)nl() | |
386 | This command copies the client's bf(sha256sum)(1) program to the | |
387 | monitor. | |
397 | 388 | |
398 | 389 | it() bf(LOCAL NOTEST) tt(<command>)nl() |
399 | Execute tt(command) on the controller, using the bf(SH) command | |
390 | Execute tt(command) on the monitor, using the bf(SH) command | |
400 | 391 | shell. The command may or may not succeed.nl() |
401 | 392 | Example:nl() |
402 | 393 | tt(LOCAL NOTEST mkdir /tmp/subdir)nl() |
403 | This command creates tt(/tmp/subdir) on the controller. The command fails | |
394 | This command creates tt(/tmp/subdir) on the monitor. The command fails | |
404 | 395 | if the directory cannot be created, but this does not terminate s(). |
405 | 396 | |
406 | it() bf(LOCAL CHECK) [bf(LOG =)] tt(<logfile> [pathOffset] <command>)nl() | |
407 | Execute tt(command) on the controller, using the bf(SH) command | |
397 | it() bf(LOCAL CHECK) [bf(LOG =)] tt(<file-spec> [pathOffset] | |
398 | <command>)nl() | |
399 | Execute tt(command) on the monitor, using the bf(SH) command | |
408 | 400 | shell. The command must succeed. The output of this command is compared to the |
409 | 401 | output of this command generated during the previous integrity check run by |
410 | s(). | |
411 | ||
412 | The phrase bf(LOG =) is optional. tt(PathOffset) is also | |
413 | optional. If specified it defines the (0-based) offset where path-names of | |
414 | inspected files start in lines produced by tt(<command>). By default s() | |
415 | assumes that the first occurrence of a forward slash defines the first | |
416 | character of the path-names of inspected files. | |
402 | s(). | |
403 | ||
404 | The phrase bf(LOG =) is optional. When a relative file location is | |
405 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
406 | path specification. | |
407 | ||
408 | tt(PathOffset) is also optional. If specified it defines the (0-based) | |
409 | offset where path-names of inspected files start in lines produced by | |
410 | tt(<command>). By default s() assumes that the first occurrence of a forward | |
411 | slash defines the first character of the path-names of inspected files. | |
417 | 412 | |
418 | 413 | For example, if diff-output looks like this: |
419 | 414 | verb( 01234567890123456789012345678901234567890 (column offsets) |
434 | 429 | (UTC) datetime-stamp at the time s() was run. |
435 | 430 | |
436 | 431 | Note that eventually many tt(logfile.YYMMDD-HHMMSS) files could be |
437 | created: It is up to the controller's systems manager to decide what to do | |
432 | created: It is up to the monitor's systems manager to decide what to do | |
438 | 433 | with old datetime-stamped logfiles. |
439 | 434 | |
440 | 435 | The tt(logfile) specifications may use relative and absolute paths. When |
443 | 438 | are created first. |
444 | 439 | |
445 | 440 | Example:nl() |
446 | tt(LOCAL CHECK LOG = local/sha1sum sha1sum /tmp/sha1sum)nl() | |
447 | This command checks the SHA1 sum of the tt(/tmp/sha1sum) program. The | |
448 | resulting output is saved at bf(BASE)tt(/local/sha1sum). The program must | |
449 | succeed (i.e., tt(sha1sum) must return a zero exit-value). | |
441 | tt(LOCAL CHECK LOG = local/sha256sum sha256sum /tmp/sha256sum)nl() | |
442 | This command checks the SHA256 sum of the tt(/tmp/sha256sum) program. The | |
443 | resulting output is saved at bf(BASE)tt(/local/sha256sum). The program must | |
444 | succeed (i.e., tt(sha256sum) must return a zero exit-value). | |
450 | 445 | |
451 | 446 | it() bf(LOCAL NOTEST CHECK) tt(<logfile> [pathOffset] <command>)nl() |
452 | Execute tt(command) on the controller, using the bf(SH) command | |
447 | Execute tt(command) on the monitor, using the bf(SH) command | |
453 | 448 | shell. The command may or may not succeed. Otherwise, the command performs |
454 | 449 | exactly like the bf(LOCAL CHECK ...) command, discussed above. |
455 | 450 | |
456 | 451 | Example:nl() |
457 | tt(LOCAL NOTEST CHECK LOG=local/sha1sum sha1sum /tmp/sha1sum)nl() | |
458 | This command checks the SHA1 sum of the tt(/tmp/sha1sum) program. The | |
459 | resulting output is saved at bf(BASE)tt(/local/sha1sum). The program must | |
460 | succeed (i.e., tt(sha1sum) must return a zero exit-value). | |
452 | tt(LOCAL NOTEST CHECK LOG=local/sha256sum sha256sum /tmp/sha256sum)nl() | |
453 | This command checks the SHA256 sum of the tt(/tmp/sha256sum) program. The | |
454 | resulting output is saved at bf(BASE)tt(/local/sha256sum). The program must | |
455 | succeed (i.e., tt(sha256sum) must return a zero exit-value). | |
461 | 456 | ) |
462 | 457 | |
463 | 458 | Note that the bf(scp)(1) command can be used to copy files between the |
464 | client and the controller, using a local command. This, however, is | |
459 | client and the monitor, using a local command. This, however, is | |
465 | 460 | discouraged, as a separate bf(ssh)(1)-connection is required for each separate |
466 | 461 | bf(scp)(1) command. This subtlety was brought to the author's attention by |
467 | 462 | Hopko Meijerink (tt(h.meijering@rug.nl)). |
468 | 463 | |
469 | New bf(ssh)(1) connections may be difficult to establish if the used | |
470 | ssh-key is passphrase-protected (but it is not impossible to do so, see e.g., | |
471 | bf(ssh-cron)(1)), and using an ssh-key without a passphrase is discouraged as | |
472 | client computers are immediagely compromised too, once the controller is | |
473 | compromised. Furthermore, using bf(scp)(1) results in several additional | |
474 | entries showing bf(sshd)(1) connections in the client's logfiles, which in | |
475 | turn may disclose information that the client is intensively monitored. | |
476 | ||
477 | To copy files between the client and the controller, the tt(GET) and | |
464 | To copy files between the client and the monitor, the tt(GET) and | |
478 | 465 | tt(PUT) commands (described below) should be used instead, as these commands |
479 | 466 | use the existing bf(ssh)(1) connection. In general, tt(LOCAL) commands should |
480 | 467 | not be used to establish additional bf(ssh)(1) connections to a client. |
489 | 476 | intended program. |
490 | 477 | |
491 | 478 | Two special remote commands are tt(GET) and tt(PUT), which can be used to |
492 | copy files between the client and the controller. Internally, tt(GET) and | |
479 | copy files between the client and the monitor. Internally, tt(GET) and | |
493 | 480 | tt(PUT) use the tt(DD) specification. If a non-default specification is |
494 | 481 | used, one should ensure that the alternate program accepts bf(dd)(1)'s tt(if=, |
495 | 482 | of=, bs=) and tt(count=) options. With tt(GET) the options tt(bs=, count=) and |
501 | 488 | itemization( |
502 | 489 | it() bf(GET) tt(<client-path> <local-path>)nl() |
503 | 490 | Copy the file indicated by tt(client-path) at the client to tt(local-path) |
504 | at the controller. tt(client-path) must be the full path of an existing file | |
505 | on the client, tt(local-path) may either be a local directory, in which case | |
506 | the client's file name is used, or another file name may be specified, in | |
491 | at the monitor. Here, tt(client-path) must be the full path of an existing | |
492 | file on the client, tt(local-path) may either be a local directory, in which | |
493 | case the client's file name is used, or another file name may be specified, in | |
507 | 494 | which case the client's file is copied to the specified local filename. If the |
508 | 495 | local file already exists, it is overwritten by the copy-procedure. |
509 | 496 | |
510 | 497 | Example:nl() |
511 | tt(GET /usr/bin/sha1sum /tmp)nl() | |
512 | The program tt(/usr/bin/sha1sum), available at the client, is copied to the | |
513 | controller's tt(/tmp) directory. If, for whatever reason, copying fails, then | |
498 | tt(GET /usr/bin/sha256sum /tmp)nl() | |
499 | The program tt(/usr/bin/sha256sum), available at the client, is copied to the | |
500 | monitor's tt(/tmp) directory. If, for whatever reason, copying fails, then | |
514 | 501 | s() terminates. |
515 | 502 | |
516 | 503 | it() bf(GET NOTEST) tt(<client-path> <local-path>)nl() |
517 | 504 | Copy the file indicated by tt(client-path) at the client to tt(local-path) |
518 | at the controller. tt(client-path) must be the full path of an existing file | |
519 | on the client, tt(local-path) may either be a local directory, in which case | |
520 | the client's file name is used, or another file name may be specified, in | |
505 | at the monitor. Again, tt(client-path) must be the full path of an existing | |
506 | file on the client, tt(local-path) may either be a local directory, in which | |
507 | case the client's file name is used, or another file name may be specified, in | |
521 | 508 | which case the client's file is copied to the specified local filename. If the |
522 | 509 | local file already exists, it is overwritten by the copy-procedure. |
523 | 510 | |
524 | 511 | Example:nl() |
525 | tt(GET NOTEST /usr/bin/sha1sum /tmp)nl() | |
526 | The program tt(/usr/bin/sha1sum), available at the client, is copied to the | |
527 | controller's tt(/tmp) directory. Remaining commands in the policy file are | |
512 | tt(GET NOTEST /usr/bin/sha256sum /tmp)nl() | |
513 | The program tt(/usr/bin/sha256sum), available at the client, is copied to the | |
514 | monitor's tt(/tmp) directory. Remaining commands in the policy file are | |
528 | 515 | executed, even if the copying process wasn't successful. |
529 | 516 | ) |
530 | 517 | |
531 | 518 | The tt(PUT) command may be used as follows: |
532 | 519 | itemization( |
533 | 520 | it() bf(PUT) tt(<local-path> <remote-path>)nl() |
534 | Copy the file indicated by tt(local-path) at the controller to | |
521 | Copy the file indicated by tt(local-path) at the monitor to | |
535 | 522 | tt(remote-path) at the client. The argument tt(local-path) must be the |
536 | full path of an existing file on the controller. The argument tt(remote-path) | |
523 | full path of an existing file on the monitor. The argument tt(remote-path) | |
537 | 524 | must be the full path to a file on the client. If the remote file already |
538 | 525 | exists, it is overwritten by tt(PUT). |
539 | 526 | |
540 | 527 | Example:nl() |
541 | tt(PUT /tmp/sha1sum /usr/bin/sha1sum)nl() | |
542 | The program tt(/tmp/sha1sum), available at the controller, is copied to the | |
543 | client as tt(usr/bin/sha1sum). If the copying fails, bf(stealth) terminates. | |
528 | tt(PUT /tmp/sha256sum /usr/bin/sha256sum)nl() | |
529 | The program tt(/tmp/sha256sum), available at the monitor, is copied to the | |
530 | client as tt(usr/bin/sha256sum). If the copying fails, bf(stealth) terminates. | |
544 | 531 | |
545 | 532 | it() bf(PUT NOTEST) tt(<local-path> <remote-path>)nl() |
546 | Copy the file indicated by tt(local-path) at the controller to | |
533 | Copy the file indicated by tt(local-path) at the monitor to | |
547 | 534 | tt(remote-path) at the client. The argument tt(local-path) must be the |
548 | full path of an existing file on the controller. The argument tt(remote-path) | |
535 | full path of an existing file on the monitor. The argument tt(remote-path) | |
549 | 536 | must be the full path to a file on the client. If the remote file already |
550 | 537 | exists, it is overwritten by tt(PUT). |
551 | 538 | |
552 | 539 | Example:nl() |
553 | tt(PUT NOTEST /tmp/sha1sum /usr/bin/sha1sum)nl() | |
554 | Copy the file indicated by tt(local-path) at the controller to | |
540 | tt(PUT NOTEST /tmp/sha256sum /usr/bin/sha256sum)nl() | |
541 | Copy the file indicated by tt(local-path) at the monitor to | |
555 | 542 | tt(remote-path) at the client. The argument tt(local-path) must be the full |
556 | path of an existing file on the controller. The argument tt(remote-path) must | |
543 | path of an existing file on the monitor. The argument tt(remote-path) must | |
557 | 544 | be the full path to a file on the client. If the remote file already exists, |
558 | 545 | it is overwritten by tt(PUT). Remaining commands in the policy file are |
559 | 546 | executed, even if the copying process wasn't successful. |
567 | 554 | |
568 | 555 | The following commands are available for execution on the client: |
569 | 556 | itemization( |
570 | it() tt(<command>)nl() | |
571 | Execute tt(command) on the client, using the bf(SSH) command | |
572 | shell. The command must succeed (i.e., must return a zero exit | |
573 | value). However, any output generated by the the command is ignored. nl() | |
557 | it() tt(<command-path>)nl() | |
558 | Execute tt(command-path) on the client using the bf(SSH) command shell | |
559 | (it is strongly advised to specify a full path to the command to execute). The | |
560 | command must succeed (i.e., must return a zero exit value). However, any | |
561 | output generated by the the command is ignored. nl() | |
574 | 562 | Example:nl() |
575 | 563 | tt(/usr/bin/find /tmp -type f -exec /bin/rm {} \;)nl() |
576 | This command will remove all ordinary files in and below the client's | |
564 | This command removes all ordinary files in and below the client's | |
577 | 565 | tt(/tmp) directory. |
578 | 566 | |
579 | it() bf(NOTEST) tt(<command>)nl() | |
580 | Execute tt(command) on the client, using the bf(SSH) command | |
567 | it() bf(NOTEST) tt(<command-path>)nl() | |
568 | Execute tt(command-path) on the client, using the bf(SSH) command | |
581 | 569 | shell. The command may or may not succeed.nl() |
582 | 570 | Example:nl() |
583 | 571 | tt(NOTEST /usr/bin/find /tmp -type f -exec /bin/rm {} \;)nl() |
584 | 572 | Same as the previous command, but this time the exit value of |
585 | 573 | tt(/usr/bin/find) is not interpreted. |
586 | 574 | |
587 | it() bf(CHECK) [bf(LOG =)] tt(<logfile> [pathOffset] <command>)nl() | |
588 | Execute tt(command) on the client, using the bf(SSH) command | |
589 | shell. The phrase bf(LOG = ) is optional. The tt([pathOffset]) specification | |
590 | is also optional, and has the same meaning as for the tt(LOCAL CHECK) command, | |
591 | described above. The command must succeed. The output of this command is | |
592 | compared to the output of this command generated during the previous run of | |
593 | s(). Any differences are written to bf(REPORT). If differences were found, the | |
594 | existing tt(logfile) name is renamed to tt(logfile.YYMMDD-HHMMSS), with | |
595 | tt(YYMMDD-HHMMSS) the datetime-stamp at the time s() was run. | |
575 | it() bf(CHECK) [bf(LOG =)] tt(<file-spec> [pathOffset] | |
576 | <command-path>)nl() | |
577 | Execute tt(command-path) on the client, using the bf(SSH) command | |
578 | shell. | |
579 | ||
580 | The phrase bf(LOG =) is optional. When a relative file location is | |
581 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
582 | path specification. | |
583 | ||
584 | tt(PathOffset) is also optional, and has the same meaning | |
585 | as for the tt(LOCAL CHECK) command, described above. The command must | |
586 | succeed. The output of this command is compared to the output of this command | |
587 | generated during the previous run of s(). Any differences are written to | |
588 | bf(REPORT). If differences were found, the existing tt(logfile) name is | |
589 | renamed to tt(logfile.YYMMDD-HHMMSS), with tt(YYMMDD-HHMMSS) the | |
590 | datetime-stamp at the time s() was run. | |
596 | 591 | |
597 | 592 | Note that the command is executed on the client, but the logfile is kept |
598 | on the controller. This command represents the core of the method implemented | |
593 | on the monitor. This command represents the core of the method implemented | |
599 | 594 | by s(): there will be no residues of the actions performed by s() on |
600 | 595 | the client computers. |
601 | 596 | |
612 | 607 | bf(BASE)tt(/remote/ls.root). |
613 | 608 | |
614 | 609 | |
615 | tt(CHECK remote/sha1.root \)nl() | |
610 | tt(CHECK remote/sha256.root \)nl() | |
616 | 611 | tt( /usr/bin/find / \)nl() |
617 | tt( -xdev -perm /6111 -type f -exec /usr/bin/sha1sum {} \;) | |
618 | ||
619 | The SHA1 checksums of all suid/gid/executable files on the same device as | |
612 | tt( -xdev -perm /6111 -type f -exec /usr/bin/sha256sum {} \;) | |
613 | ||
614 | The SHA256 checksums of all suid/gid/executable files on the same device as | |
620 | 615 | the root-directory (/) on the client computer are determined. The resulting |
621 | listing is written on the file bf(BASE)tt(/remote/sha1.root). | |
622 | ||
623 | it() bf(NOTEST CHECK) [bf(LOG =)] tt(<logfile> [pathOffset] <command>)nl() | |
624 | Execute tt(command) on the client, using the bf(SSH) command | |
625 | shell. The phrase bf(LOG =) is optional. The tt([pathOffset]) is also | |
626 | optional, and has the same meaning as for the tt(LOCAL CHECK) command, | |
627 | described above. The command may or may not succeed. Otherwise, the program | |
628 | acts identically as the bf(CHECK ...) command, described above. | |
629 | ||
630 | Example:nl() | |
631 | tt(NOTEST CHECK LOG = remote/sha1.root \)nl() | |
616 | listing is written on the file bf(BASE)tt(/remote/sha256.root). | |
617 | ||
618 | it() bf(NOTEST CHECK) [bf(LOG =)] tt(<file-spec> [pathOffset] | |
619 | <command-path>)nl() | |
620 | Execute tt(command-path) on the client, using the bf(SSH) command | |
621 | shell. | |
622 | ||
623 | The phrase bf(LOG =) is optional. When a relative file location is | |
624 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
625 | path specification. | |
626 | ||
627 | tt(PathOffset) is also optional, and has the same meaning as for the tt(LOCAL | |
628 | CHECK) command, described above. The command may or may not | |
629 | succeed. Otherwise, the program acts identically as the bf(CHECK ...) command, | |
630 | described above. | |
631 | ||
632 | Example:nl() | |
633 | tt(NOTEST CHECK LOG = remote/sha256.root \)nl() | |
632 | 634 | tt( /usr/bin/find / \)nl() |
633 | tt( -xdev -perm /6111 -type f -exec /usr/bin/sha1sum {} \;) | |
634 | ||
635 | ||
636 | The SHA1 checksums of all suid/gid/executable files on the same device as | |
635 | tt( -xdev -perm /6111 -type f -exec /usr/bin/sha256sum {} \;) | |
636 | ||
637 | ||
638 | The SHA256 checksums of all suid/gid/executable files on the same device as | |
637 | 639 | the root-directory (/) on the client computer are determined. The resulting |
638 | listing is written on the file bf(BASE)tt(/remote/sha1.root). s() does not | |
640 | listing is written on the file bf(BASE)tt(/remote/sha256.root). s() does not | |
639 | 641 | terminate if the tt(/usr/bin/find) program returns a non-zero exit value. |
640 | 642 | ) |
641 | 643 | |
643 | 645 | tt(--max-size) option, see below. By default this size is set at 10M. |
644 | 646 | |
645 | 647 | |
646 | manpagesection(OPTIONS) | |
647 | ||
648 | includefile(../manual/running/options.yo) | |
648 | manpagesection(REPORT FILE ROTATION) | |
649 | Since s() only appends information to the report file, the report file's | |
650 | size may eventually become prohibitively large, and log-rotation may be | |
651 | desirable. It is of course possible to issue a tt(--terminate) command, rotate | |
652 | the logfiles, and restart s(), but s() also offers a facility to temporarily | |
653 | suspend integrity scans performed by a s() daemon process: | |
654 | itemization( | |
655 | it() Calling s() with the option tt(--suspend <uds>) suspends the | |
656 | daemon's integrity scans. If s() is | |
657 | actually performing a series of integrity scans when | |
658 | tt(--suspend) is issued, the currently executing command is first | |
659 | completed after which the tt(--suspend) command completes. Once | |
660 | the s() daemon has been suspended, automatic or explicit | |
661 | integrity scan requests are denied, and the daemon can only be | |
662 | instructed to resume its scanning tasks (s() --resume <uds>) | |
663 | or to terminate (s() --terminate <uds>). | |
664 | ||
665 | it() Once `s() tt(--suspend <uds>)' has returned, the report file | |
666 | may safely be rotated (using, e.g., bf(logrotate)(1)), and a new | |
667 | (empty) report file may optionally be created by the logrotation | |
668 | process. | |
669 | ||
670 | it() Once the log-rotation has been completed, the log-rotation process | |
671 | should issue the command `s() tt(--resume <uds>)'. This | |
672 | resumes the activities of a suspended s() daemon process, | |
673 | immediately performing the next integrity scan. Following this the | |
674 | s() daemon is back to its original integrity scanning mode. | |
675 | ) | |
676 | Here is an example of bf(logrotate)(1) specification rotating s() | |
677 | log-files: | |
678 | verb( | |
679 | /root/stealth/clienthost/small/report /var/log/stealth/clienthost-small.log { | |
680 | daily | |
681 | rotate 4 | |
682 | compress | |
683 | missingok | |
684 | copytruncate | |
685 | sharedscripts | |
686 | prerotate | |
687 | /usr/bin/stealth --suspend /root/stealth/client/small.uds | |
688 | endscript | |
689 | postrotate | |
690 | /usr/bin/stealth --resume /root/stealth/client/small.uds | |
691 | endscript | |
692 | } | |
693 | ) | |
694 | ||
695 | manpagesection(RELOAD, RERUN AND TERMINATE) | |
696 | ||
697 | Here is what happens when s() is run using the third synopsis: | |
698 | ||
699 | itemization( | |
700 | it() When started as s() tt(--reload <uds>), the s() daemon process | |
701 | reloads its policy file and (if specified) tt(--skip-files) | |
702 | specification file. Next the s() daemon process performs a file | |
703 | integrity scan using the information in the re-read policy and | |
704 | skip-files files. S() can reload the (modified) contents of the | |
705 | originally specified policy- and skip-files names. If another policy | |
706 | and/or skip-files files must be used another s() process must be | |
707 | started, for which these new filenames are specified. | |
708 | ||
709 | it() When started as s() tt(--rerun <uds>), the s() daemon performs | |
710 | another scan (unless it has been suspended using s() tt(--suspend | |
711 | <uds>)). | |
712 | ||
713 | it() When started as s() tt(--terminate <uds>), the s() daemon is | |
714 | terminated. | |
715 | ) | |
649 | 716 | |
650 | 717 | manpagesection(RSYSLOG FILTERING) |
651 | 718 | |
658 | 725 | itemization( |
659 | 726 | it() Install s() (e.g., use bf(dpkg)(1) to install the bf(.deb) file); |
660 | 727 | it() Construct one or more policy files; |
661 | it() Automate running s() using bf(cron)(1) (possibly calling | |
662 | bf(stealthcron)); | |
728 | it() Automate (re)starting s() using bf(cron)(1) or bf(ssh-cron)(1) | |
729 | (possibly calling bf(stealthcron)); | |
663 | 730 | it() Set up automated log-file rotation, using, e.g., bf(stealthcleanup) |
664 | 731 | and bf(logrotate)(1), defining one or more |
665 | 732 | tt(/etc/logrotate.d/stealth...) configuration files. |
674 | 741 | |
675 | 742 | manpageseealso() |
676 | 743 | bf(cron)(1), bf(dd)(1), bf(diff)(1), bf(dpkg)(1), bf(find)(1), |
677 | bf(logrotate)(1), bf(ls)(1), bf(mail)(1), bf(sha1sum)(1), bf(passwd)(5), | |
744 | bf(logrotate)(1), bf(ls)(1), bf(mail)(1), bf(sha256sum)(1), bf(passwd)(5), | |
678 | 745 | bf(rsyslog)(1), bf(sendmail)(1), bf(sh)(1), bf(ssh)(1), bf(ssh-cron)(1) |
679 | 746 | |
680 | 747 | manpagesection(DIAGNOSTICS) |
0 | ||
1 | 0 | Next, at the client's account where s()'s tt(ssh) command connects to (see |
2 | also the tt(USE SSH) specification in section ref(USE) ssh-access must be | |
3 | granted to the controller's user. To do so, the controller user's file | |
1 | also the tt(USE SSH) specification in section ref(USE)) ssh-access must be | |
2 | granted to the monitor's user. To do so, the monitor user's file | |
4 | 3 | tt(~/.ssh/id_rsa.pub) is added to the client account user's file |
5 | 4 | tt(~/.ssh/authorized_keys): |
6 | verb( # transfer user@controller's file id_rsa.pub to the client's /tmp | |
5 | verb( # transfer user@monitor's file id_rsa.pub to the client's /tmp | |
7 | 6 | # directory. Then do: |
8 | 7 | |
9 | 8 | cat /tmp/id_rsa.pub >> /home/account/.ssh/authorized_keys) |
10 | 9 | |
11 | This allows the user at the controller to login at the account at the | |
10 | This allows the user at the monitor to login at the account at the | |
12 | 11 | client without specifying the client account's password (of course, if the |
13 | 12 | ssh-key is passphrase protected that passphrase must still be provided at the |
14 | controller once s() is started). | |
13 | monitor when starting s()). | |
15 | 14 |
0 | The controller's user calling s() to scan the client must first generate | |
1 | an tt(ssh-keypair): | |
2 | verb( ssh-keygen -t rsh) | |
3 | This generates a public/private ssh key pair in tt(.ssh) in the user's | |
4 | home directory. The program asks for a em(passphrase). A passphrase can be | |
5 | defined (in which case it must be proviced when s() is started) or, if the | |
6 | security if the controller is sufficiently guaranteed, it can remain empty. To | |
7 | generate an ssh-key without passphrase simply press tt(Enter) in response to | |
8 | the question | |
9 | verb( Enter passphrase (empty for no passphrase):) | |
10 | (a confirmation is required: just press tt(Enter) again). | |
11 | ||
12 | tt(Ssh-keygen) then returns a key fingerprint, e.g., | |
13 | verb( 03:96:49:63:8a:64:33:45:79:ab:ca:de:c8:c8:4f:e9 user@controller) | |
14 | which may be saved for future reference. | |
15 | ||
16 | In the user's tt(.ssh) directory the files tt(id_rsa) and tt(id_rsa.pub) | |
17 | are now created, which completes the preparations at the controller. |
0 | Access to clients (remote hosts) must be granted using the tt(ssh) protocol. | |
0 | Access to clients should be granted using the tt(ssh) protocol. | |
1 | 1 | |
2 | Clients must allow the controller to connect using tt(ssh). S() connects to | |
3 | its clients using ssh certificates, after the controler's public | |
4 | key has been transferred to its clients. | |
2 | Clients must allow the monitor to connect using tt(ssh). S() connects to its | |
3 | clients using ssh certificates, after the monitor's public SSH-key has been | |
4 | transferred to the clients. |
0 | When user@controller now issues, for the first time, the command | |
1 | verb( ssh account@controller) | |
0 | When user@monitor now issues, for the first time, the command | |
1 | verb( ssh account@monitor) | |
2 | 2 | tt(Ssh) responds like this: |
3 | verb( The authenticity of host 'controller (xxx.yyy.aaa.bbb)' can't be | |
3 | verb( The authenticity of host 'monitor (xxx.yyy.aaa.bbb)' can't be | |
4 | 4 | established. |
5 | 5 | RSA key fingerprint is c4:52:d6:a3:d4:65:0d:5e:2e:66:d8:ab:de:ad:12:be. |
6 | 6 | Are you sure you want to continue connecting (yes/no)?) |
7 | 7 | Answering tt(yes) results in the message: |
8 | verb( Warning: Permanently added 'controller,xxx.yyy.aaa.bbb' (RSA) to the | |
8 | verb( Warning: Permanently added 'monitor,xxx.yyy.aaa.bbb' (RSA) to the | |
9 | 9 | list of known hosts.) |
10 | 10 | |
11 | The next time a login is attempted, the authenticity question isn't asked | |
11 | The next time a login is attempted, the authenticity question is not asked | |
12 | 12 | anyore. However, the proper value of the host's RSA key fingerprint (i.e., the |
13 | 13 | key fingerprint of the em(client) computer) should em(always) be verified to |
14 | 14 | prevent em(man in the middle) attacks. The proper value may be obtained at the |
15 | client computer by issuing (at the client) the command | |
15 | client by issuing there the command | |
16 | 16 | verb( ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub) |
17 | 17 | This should show the same value of the fingerprint as shown when the |
18 | 18 | first tt(ssh) connection was established. E.g., |
19 | verb( 1024 c4:52:d6:a3:d4:65:0d:5e:2e:66:d8:ab:de:ad:12:be ssh_host_rsa_key.pub) | |
19 | verb( | |
20 | 1024 c4:52:d6:a3:d4:65:0d:5e:2e:66:d8:ab:de:ad:12:be ssh_host_rsa_key.pub) |
0 | The monitor's user calling s() to scan the client must first generate | |
1 | an tt(ssh-keypair): | |
2 | verb( ssh-keygen -t rsa) | |
3 | By default this generates a public/private ssh key-pair in the directory | |
4 | tt(.ssh) in the user's home directory. The program asks for a | |
5 | em(passphrase). A passphrase can be defined (in which case it must be proviced | |
6 | when s() is started) or, if the security if the monitor is sufficiently | |
7 | guaranteed, it can remain empty. To generate an ssh-key without passphrase | |
8 | simply press tt(Enter) in response to the question | |
9 | verb( Enter passphrase (empty for no passphrase):) | |
10 | (a confirmation is required: just press tt(Enter) again). | |
11 | ||
12 | tt(Ssh-keygen) then returns a key fingerprint, e.g., | |
13 | verb( 03:96:49:63:8a:64:33:45:79:ab:ca:de:c8:c8:4f:e9 user@monitor) | |
14 | which may be saved for future reference. | |
15 | ||
16 | In the user's tt(.ssh) directory the files tt(id_rsa) and tt(id_rsa.pub) | |
17 | are now created, which completes the preparations at the monitor. | |
18 | ||
19 | If, instead of running s() in deamon mode it is preferred to let s() perform | |
20 | single, but automated integrity scans, then new bf(ssh)(1) connections may be | |
21 | difficult to establish if the used ssh-key is passphrase-protected. To | |
22 | implement this scenario (i.e., automated integrity scans using passphrase | |
23 | protected ssh-keys) the program bf(ssh-cron)(1) can profitably be used. | |
24 |
0 | On order to minimize the amount of clutter and possible complications when | |
0 | On order to minimize the amount of clutter and possibly complications when | |
1 | 1 | only a simple command-shell is required for executing commands, it is |
2 | 2 | suggested to use a bf(bash)(1) shell when logging into tt(account@client)'s |
3 | 3 | account. |
0 | COMMENT( | |
1 | tt(/bin/sh: no output from /usr/bin/diff ...) | |
2 | quote(the actual program names appearing here could change due to your | |
3 | local configuration. The defaults are shown. This indicates that the | |
4 | tt(/usr/bin/diff) program could not be activated on the controller. Check the | |
5 | correctness of both the shell program (tt(/bin/sh)) and the diff program | |
6 | (tt(/usr/bin/diff)): Do they exist? Have their paths been specfied well? | |
7 | Note that filenames passed to tt(diff) might not exist anymore when the | |
8 | program terminates. This should not be the cause of the error. | |
9 | ) | |
10 | END) | |
11 | ||
12 | 0 | tt(Can't chdir to `path') |
13 | 1 | quote(the directory tt(path) could not be |
14 | 2 | created/used. This may be a permission problem. Check the permissions of |
23 | 11 | write it. |
24 | 12 | ) |
25 | 13 | |
14 | tt(Corrupt line in policy file: ...) | |
15 | quote(The apparently corrupted line is shown. The line is corrupted if | |
16 | the line could not be split into an initial word and its remainder. Normally | |
17 | this should not happen. As the line is mentioned, the message itself should | |
18 | assist you in your repairs. | |
19 | ) | |
20 | ||
26 | 21 | tt(could not open <logname>) |
27 | 22 | quote(This message is generated when the mentioned log-file cannot be |
28 | 23 | written to. Check the permissions of the file, and check if the path to the |
30 | 25 | last element of the path or in the file itself. |
31 | 26 | ) |
32 | 27 | |
33 | tt(Can't read `<run-file>') | |
34 | quote(The daemon's run-file could not be read. Check if there is indeed a | |
35 | s() daemon process using this run-filefile exists; if the run-file actually | |
36 | exists (typo in its specification?), and if you have read permissions for it. | |
37 | ) | |
38 | ||
39 | tt(Can't send signal <signal-name> to process `<pid>') | |
40 | quote(The indicated signal (either tt(SIGTERM) or tt(SIGUSR1)) could not | |
41 | be sent to the daemon process. Check if a s() daemon process having process ID | |
42 | tt(<pid>) really exist.) | |
43 | ||
44 | tt(Corrupt line in policy file: ...) | |
45 | quote(The apparently corrupted line is shown. The line is corrupted if | |
46 | the line could not be split into an initial word and its remainder. Normally | |
47 | this should not happen. As the line is mentioned, the message itself should | |
48 | assist you in your repairs. | |
49 | ) | |
50 | ||
51 | tt(could not write <run-file name>) | |
52 | quote(The specified run-file could not be written to. Check its | |
53 | permissions and whether it actually exists.) | |
54 | ||
55 | tt(--daemon: missing run-file or policy file) | |
56 | quote(The tt(--daemon) option requires an absolute filename to a run-file, | |
57 | and the call also requires a policy file. Most likely the path to the run-file | |
58 | was not specified, thus confusing the policy file with the run-file. The | |
59 | run-file is often created in the tt(/run) directory. | |
60 | ) | |
61 | ||
62 | tt(--daemon <run-file>: must use an absolute file name) | |
63 | quote(The tt(--daemon) option requires a full (absolute) path to the | |
64 | run-file name. Most likely the name of the run-file was not specified, thus | |
65 | confusing the policy file with the skip-file. The run-file is often created in | |
66 | the tt(/run) directory. | |
28 | tt(--daemon: missing uds-file or policy file) | |
29 | quote(The tt(--daemon) option requires the location for its Unix Domain | |
30 | Socket, and in addition a policy file must be specified. Most likely the | |
31 | location of the Unix Domain File was omitted, thus confusing the policy file | |
32 | with the Unix Domain File | |
33 | ) | |
34 | ||
35 | ||
36 | tt(incompatible options: ...) | |
37 | quote(Two or more incompatible options are shown. E.g., tt(--daemon) is | |
38 | incompatible with IPC options, which themselves are mutually | |
39 | incompatible. Omit all but one of the mentioned options and restart s() | |
67 | 40 | ) |
68 | 41 | |
69 | 42 | tt(Inserting command `...' failed.) |
77 | 50 | negative) argument. |
78 | 51 | ) |
79 | 52 | |
80 | tt(incompatible options: ....) | |
81 | quote(Only one option related to a s() daemon process can be specified at | |
82 | a time. E.g., you cannot specify tt(--daemon --rerun --suspend) in one | |
83 | command. If incompatible options are specified s() terminates after reporting | |
84 | which (incompatible) options were received.) | |
53 | tt(invalid --<option> specified) | |
54 | quote(The specified option value (e.g., tt(--max-size) was specified, but | |
55 | its option value is not a valid integral number) is not supported | |
56 | ) | |
57 | ||
58 | tt(LocalClientSocket::connect(): ...) | |
59 | quote(When running in IPC-mode s() could not connect to the unix domain | |
60 | socket specified for the IPC-mode. Check whether the matching s() daemon | |
61 | exists, and whether the location of the uds-file was correctly specified | |
62 | ) | |
63 | ||
64 | tt(LocalServerSocket::accept(): ...) | |
65 | quote(When running in daemon mode incoming connections could not be | |
66 | accepted. This may have many causes, and a probably cause is mentioned with | |
67 | the error message | |
68 | ) | |
69 | ||
70 | tt(LocalServerSocket::listen(): ...) | |
71 | quote(When running in daemon mode the unix domain socket failed to | |
72 | listen for incoming connections. This may have many causes, and a probably | |
73 | cause is mentioned with the error message | |
74 | ) | |
75 | ||
76 | tt(LocalServerSocket::open(<uds>): ...) | |
77 | quote(When running in daemon mode the unix domain socket could not be | |
78 | opened. A possible reason is that an entry in the file system having the same | |
79 | name already exists. The error message will mention a probably cause of the | |
80 | failure | |
81 | ) | |
85 | 82 | |
86 | 83 | tt(--max-size incompatible with IPC calls) |
87 | 84 | quote(The tt(--max-size) option can can only be used when s() is also |
99 | 96 | terminates. |
100 | 97 | ) |
101 | 98 | |
102 | tt(--<option name> is only valid for a stealth foreground process) | |
103 | quote(The specified option is incompatible with the tt(--daemon) | |
104 | option. Either do not specify tt(--daemon) or omit the offending option.) | |
99 | tt(--<option> is only valid for a s() foreground process) | |
100 | quote(The indicated option cannot be specified in combination with a | |
101 | tt(--daemon) or IPC-option (like tt(--suspend)) | |
102 | ) | |
105 | 103 | |
106 | 104 | tt(--random-interval requires --repeat) |
107 | 105 | quote(The tt(--random-interval) option can only be used when the |
108 | 106 | tt(--repeat) option has also been specified. |
107 | ) | |
108 | ||
109 | tt(--repeat not available in IPC modes) | |
110 | quote(The tt(--repeat) option cannot be specified in combination with an | |
111 | IPC-option (like tt(--suspend)) | |
109 | 112 | ) |
110 | 113 | |
111 | 114 | tt(--run-command 0: not a valid (natural) command number) |
120 | 123 | ) |
121 | 124 | |
122 | 125 | tt(--skip-files incompatible with IPC calls) |
123 | quote(The tt(--skip-files) option can only be used when s() is also | |
124 | receiving a policy file. It cannot be used in combination with the Inter | |
125 | Process Communication (IPC) options tt(--reload, --rerun, --resume, --suspend) | |
126 | or tt(--terminate). | |
126 | quote(The tt(--skip-files) option can only be used when s() is also given | |
127 | a policy file. It cannot be used in combination with IPC options (tt(--reload, | |
128 | --rerun, --resume, --suspend) or tt(--terminate)). | |
127 | 129 | ) |
128 | 130 | |
129 | 131 | tt(--skip-files: missing skip-file or policy file) |
130 | quote(The tt(--skip-files) option requires a skip-files absolute filename, | |
131 | and the call also requires a policy file. Most likely the name of the | |
132 | skip-file was not specified, thus confusing the policy file with the | |
133 | skip-file. | |
134 | ) | |
135 | ||
136 | tt(--skip-files <filename>: must use an absolute file name) | |
137 | quote(The tt(--skip-files) option requires a full (absolute) path to the | |
138 | skip-file name. Most likely the name of the skip-file was not specified, thus | |
139 | confusing the policy file with the skip-file. | |
140 | ) | |
141 | ||
142 | tt(Stealth V _CurVers_ terminated) | |
143 | quote(Some pre-3.00.00 options were discontinued starting at s() version | |
144 | 3.00.00. Two of these options are tt(--suppress) and tt(--keep-alive). If | |
145 | these options are used, their use is reported and s() terminates with the | |
146 | above message. | |
132 | quote(The tt(--skip-files) option requires a file name and the s() command | |
133 | also requires a policy file. Most likely the name of the skip-file was not | |
134 | provided, thus confusing the policy file with the skip-file. | |
147 | 135 | ) |
148 | 136 | |
149 | 137 | tt(--stdout incompatible with --daemon) |
157 | 145 | tt(LOCAL7) and tt(USER). See, e.g., the bf(syslog)(3) man-page for an overview |
158 | 146 | of their definitions.) |
159 | 147 | |
148 | ||
160 | 149 | tt(--syslog* options incompatible with IPC calls) |
161 | 150 | quote(tt(--syslog*) options can can only be used when s() is also |
162 | 151 | receiving a policy file. It cannot be used in combination with the Inter |
163 | 152 | Process Communication (IPC) options tt(--reload, --rerun, --resume, --suspend) |
164 | 153 | or tt(--terminate). |
165 | 154 | ) |
166 | ||
167 | 155 | |
168 | 156 | tt(syslog priority <priority> not supported) |
169 | 157 | quote(The option tt(--syslog-priority) requires the name of a standard |
174 | 162 | WARNING) rather than tt(--syslog-priority LOG-WARNING)) |
175 | 163 | ) |
176 | 164 | |
177 | ||
178 | 165 | tt(terminated: non-zero exit value for `...') |
179 | 166 | quote(A local command (not using the tt(CHECK) keyword), returned with a |
180 | 167 | non-zero exit. This will terminate further processing of the policy |
190 | 177 | itself. |
191 | 178 | ) |
192 | 179 | |
180 | tt(Unix Domain Socket `<uds>': already in use, remove it first) | |
181 | quote(The intended Unix Domain Socket name (tt(<uds>)) is already in | |
182 | use. It could be a file that is or has been used by another process. Either | |
183 | use another name for the unix domain socket, or remove the existing | |
184 | file-system entry) | |
185 | ||
193 | 186 | tt(USE SSH ... entry missing in the policy file) |
194 | 187 | quote(there is no default for the tt(USE SSH) specification in the policy |
195 | 188 | file. The specification could not be found. Provide a specification like: |
196 | 189 | verb(USE SSH ssh -q root@localhost) |
197 | 190 | ) |
191 | ||
192 | ||
193 | ||
194 | ||
195 | ||
196 | ||
197 | ||
198 | ||
199 | ||
200 | ||
201 |
2 | 2 | is a version number. Below, tt(_CurVers_) should be altered into the version |
3 | 3 | of the archive that is actually used. |
4 | 4 | |
5 | Required, non-standard software, for compiling s() is summarized in the file | |
6 | tt(required), which is included in the source file distribution. Currently, | |
7 | its contents are: | |
8 | ||
9 | verbinclude(../../../required) | |
10 | ||
5 | 11 | itemization( |
6 | 12 | it() S() compilation is controlled by bf(icmake)(1). The program |
7 | 13 | maintenance utility bf(icmake)(1) can be obtained at |
8 | 14 | lurl(http://icmake.sourceforge.net/), and it is also available in several |
9 | Linux distributions (e.g., Debian, Ubuntu). It is assumed below | |
10 | that you have an install a recent tt(icmake) version; | |
15 | Linux distributions (e.g., Debian, Ubuntu); | |
11 | 16 | |
12 | it() Determine a directory under which the archive's file should be | |
13 | stored. E.g., if the files in the archive should be stored under tt(/tmp), and | |
14 | the archive itself is stored in tt(/tmp) as well, do: | |
17 | it() Determine a directory where the files in s()'s archive ashould be | |
18 | stored. E.g., if the files in the archive should be stored under tt(/tmp) | |
19 | (and assuming the archive itself is stored in tt(/tmp) as well) then do: | |
15 | 20 | verb( |
16 | 21 | cd /tmp |
17 | 22 | tar xzf stealth-_CurVers_.tar.gz |
18 | 23 | ) |
19 | 24 | This creates a subdirectory tt(stealth) containing s()'s sources; |
20 | 25 | |
21 | it() Next, tt(chdir) to that directory: | |
26 | it() Change-dir to that directory: | |
22 | 27 | verb( |
23 | 28 | chdir stealth |
24 | 29 | ) |
25 | 30 | |
26 | 31 | it() Check the contents of the files tt(INSTALL.im) and tt(icmconf), and |
27 | 32 | verify that all tt(#defines) match your computer's file system and |
28 | software. Also note, in tt(icmconf), the entry | |
29 | verb( | |
30 | #define ADD_LIBRARIES "bobcat" | |
31 | ) | |
33 | software. | |
32 | 34 | |
33 | When compiling and s(), the | |
35 | When compiling s(), the | |
34 | 36 | url(bobcat)(http://bobcat.sourceforge.net/) header files must be |
35 | 37 | available. When s() is run it is dynamically linked against the bobcat |
36 | library. If you haven't installed bf(bobcat) yet, download it from | |
37 | lurl(http://sourceforge.net/projects/bobcat/), and follow its installation | |
38 | instructions (alternatively, bobcat may be available in your distribution, | |
39 | like Debian or Ubuntu). Make sure to install both the run-time | |
38 | library. bf(Bobcat) can be downloaded from | |
39 | lurl(http://sourceforge.net/projects/bobcat/) (and follow its installation | |
40 | instructions). Alternatively, bobcat may be available in your distribution, | |
41 | (e.g., Debian or Ubuntu). Make sure to install both the run-time | |
40 | 42 | (bf(bobcat_...)) and the development (bf(bobcat-dev_...)) versions. |
41 | 43 | |
42 | 44 | it() Execute the command |
62 | 64 | `/usr/share/doc/stealth-doc') |
63 | 65 | ) |
64 | 66 | ) |
65 | ||
66 | ||
67 | ||
68 | ||
69 | ||
70 | ||
71 | ||
72 | ||
73 | ||
74 | ||
75 |
9 | 9 | itemization( |
10 | 10 | it() tt(SSH-based): The file integrity scan is (usually) performed over an |
11 | 11 | ssh-connection. Usually the computer being scanned (called the em(client)) and |
12 | the computer initiating the scan (called the tt(controller)) are different | |
12 | the computer initiating the scan (called the tt(monitor)) are different | |
13 | 13 | computers. |
14 | it() The client should accept incoming ssh-connections | |
15 | from the initiating computer. The controller doesn't have to (and shouldn't, | |
16 | probably). | |
14 | it() The client should accept incoming ssh-connections from the | |
15 | monitor. The monitor doesn't have to (and shouldn't, probably). | |
17 | 16 | it() tt(Trust Enforcement): following the scan, `trust' is enforced in the |
18 | 17 | client, due to the integrity of its files. |
19 | it() tt(Locally Trusted Host): the client apparently trusts the controller | |
18 | it() tt(Locally Trusted Host): the client apparently trusts the monitor | |
20 | 19 | to use an ssh-connection to perform commands on it. The client therefore |
21 | em(locally trusts) the controller. Hence, em(locally trusted host). | |
20 | em(locally trusts) the monitor. Hence, em(locally trusted host). | |
22 | 21 | ) |
23 | 22 | |
24 | 23 | s() is based on an idea by em(Hans Gankema) and em(Kees Visser), |
29 | 28 | s() has em(stealthy) characteristics. I consider this an important |
30 | 29 | security improving feature of s(). |
31 | 30 | |
32 | The controller itself only needs two kinds of outgoing services: | |
31 | The monitor itself only needs two kinds of outgoing services: | |
33 | 32 | bf(ssh)(1) to reach its clients, and some mail transport agent (e.g., |
34 | 33 | bf(sendmail)(1)) to forward its outgoing mail to some mail-hub. |
35 | 34 | |
36 | 35 | Here is what happens when s() is run: |
37 | 36 | itemization( |
38 | it() First, a em(policy) file is read. This determines actions to be | |
39 | performed, as well as the values of several variables used by s(). | |
40 | it() If the command-line option tt(--daemon) is given, s() runs as a | |
41 | backgrond (daemon) process, writing its process ID in a separate file. Using | |
42 | tt(--repeat <seconds>) the scan is rerun every tt(<seconds>) seconds after | |
43 | completing the previous integrity scan. When merely tt(--daemon) is | |
44 | specified the scan is performed only once, whereafter s() waits until it is | |
45 | reactivated through the s() tt(--rerun <pid>) command. | |
46 | it() Then, the controller opens a command shell on the client using | |
47 | bf(ssh)(1), and a command shell on the controller itself using bf(sh)(1). | |
48 | it() Next, commands defined in the policy file are executed in their order | |
49 | of appearance. Examples are given below. Normally, return values of the | |
50 | programs are tested. Non-zero return values terminate s(). | |
51 | it() In most cases, integrity tests can be controlled by the bf(find)(1) | |
52 | program, calling programs like bf(ls)(1), bf(sha1sum)(1) or its own tt(-printf) | |
53 | method to produce file-integrity related statistics. Most of these programs | |
54 | write file names at the end of generated lines. This characteristic is used by | |
55 | an internal routine of s() to detect changes in the generated output, | |
56 | which could indicate some malignant software, like an installed em(root-kit). | |
57 | it() When changes are detected, they are logged on a em(report file), to | |
58 | which information is always appended. s() never reduces or rewrites | |
59 | the report file. When information is added to the report file the newly | |
60 | written information is emailed to a configurable email address for further | |
61 | (human) processing. Usually the e-mail is sent to the systems manager of the | |
62 | tested client. s() follows the `dark cockpit' approach in that no mail | |
63 | is sent when no changes were detected. | |
37 | it() First, the em(policy) file is read. For each client a policy file is | |
38 | defined, specifying the actions to be performed, and specifying the values of | |
39 | several variables used by s(). | |
40 | ||
41 | it() If the command-line option tt(--daemon <uds>) is specified, s() | |
42 | runs as a daemon process, using the Unix Domain Socket (tt(<uds>)) for | |
43 | communication with s() processes running in IPC mode. | |
44 | ||
45 | If access to the Unix Domain Socket defined by Stealth running in daemon mode | |
46 | should be restricted, it can be defined in a directory with is only accessible | |
47 | to the user running Stealth (this will often be the root-user). | |
48 | ||
49 | When running in daemon mode, tt(--repeat <seconds>) may be specified to rerun | |
50 | the integrity scan every tt(<seconds>) seconds. If an integrity scan is being | |
51 | performed when, according to the repeat interval the next integrity scan is | |
52 | due, then the current scan is first completed. Once completed, the next | |
53 | integrity scan will be performed after tt(seconds) seconds. | |
54 | ||
55 | it() Next, the monitor opens a command shell on the client using | |
56 | bf(ssh)(1), and a command shell on the monitor computer itself using | |
57 | bf(sh)(1). | |
58 | ||
59 | it() Once the command shells are available, commands defined in the policy | |
60 | file are executed in their order of appearance. Examples are given | |
61 | below. Normally, return values of the programs are tested. When return values | |
62 | are to be tested s() terminates when a non-zero return value is sensed. If | |
63 | this happens, a message stating the reason why s() terminated is written to | |
64 | the report file (and into the mail sent by s()). In some cases (e.g., when the | |
65 | report file could not be written), the message is written to the standard | |
66 | error stream. | |
67 | ||
68 | it() Very often integrity tests can be controlled using bf(find)(1), | |
69 | calling programs like bf(ls)(1), bf(sha1sum)(1) or its own tt(-printf) method | |
70 | to produce file-integrity related statistics. Most of these programs write | |
71 | file names at the end of generated lines. This characteristic is used by one | |
72 | of s()'s internal routines to detect changes in the generated output. Such | |
73 | changes could indicate some harmful intent, like an installed em(root-kit). | |
74 | ||
75 | it() When changes are detected, they are logged in a em(report file), to | |
76 | which information is always appended. S() never reduces the report file's size | |
77 | or rewrites its contents. When information is added to the report file (beyond | |
78 | a plain time stamp) the newly added information is e-mailed to a configurable | |
79 | e-mail address for further (human) processing. Usually the e-mail is sent to | |
80 | the systems manager of the tested client. S() follows the `dark cockpit' | |
81 | approach in the sense that no mail is sent when no changes were detected. | |
82 | ||
83 | it() Report and other log-files may safely be rotated between a pair of | |
84 | tt(--suspend) and tt(--resume) commands (see below at the section | |
85 | ref(ROTATE)). | |
64 | 86 | ) |
65 | 87 | |
66 | Alternatively, the command-line options tt(--reload, --rerun, --suspend, | |
67 | --resume) and tt(--terminate) may be provided to communicate with an existing | |
68 | s() daemon. These options require but one argument: the pathname to a pid-file | |
69 | of a running s(). | |
88 | Instead of running in daemon mode, s() may also run in `foreground' mode. | |
89 | In foreground mode the option tt(--daemon) is not specified. When running in | |
90 | foreground mode s() either performs one integrity scan (and terminates) or, if | |
91 | the tt(--repeat) option has been specified, it repeatedly performs integrity | |
92 | scans, at intervals determined by the tt(--repeat) and tt(--random-interval) | |
93 | options. When tt(--repeat) is specified with s() running in foreground mode a | |
94 | prompt is shown (i.e., `tt(? )') with s() terminating after pressing the | |
95 | tt(Enter)-key. | |
96 | ||
97 | Alternatively, s() may run in `inter process communication' mode (IPC | |
98 | mode). IPC mode is characterized by using one of the command-line options | |
99 | tt(--reload, --rerun, --suspend, --resume) or tt(--terminate). In IPC-mode s() | |
100 | communicates with an existing s() daemon, using the Unix Domain Socket defined | |
101 | by the s() daemon. These options require but one argument: the location of the | |
102 | Unix Domain Socket defined by a running s() daemon. | |
70 | 103 | itemization( |
71 | it() When started using the tt(--reload <pidfile>) command-line option, | |
72 | the stealth daemon corresponding to tt(pidfile) reloads its policy and skip | |
73 | files, immediately followed by another integrity scan; | |
74 | it() When started using the tt(--rerun <pidfile>) command-line option, the | |
75 | stealth daemon corresponding to tt(pidfile) performs another integrity scan; | |
76 | it() When started using the tt(--terminate <pid>) command-line option, the | |
77 | stealth daemon corresponding to tt(pidfile) terminates. The daemon is also | |
78 | terminated if it receives a tt(SIGTERM) or tt(SIGINT) signal. | |
104 | it() When started using the tt(--reload <uds>) command-line option, the | |
105 | stealth daemon that created the Unix Domain Socket reloads its policy file | |
106 | (and skip-file), immediately followed by another integrity scan; | |
107 | it() When started using the tt(--rerun <uds>) command-line option, the | |
108 | stealth daemon that created the Unix Domain Socket performs another integrity | |
109 | scan; | |
110 | it() When started using the tt(--terminate <usd>) command-line option, the | |
111 | stealth daemon that created the Unix Domain Socket terminates. | |
79 | 112 | ) |
80 | 113 | |
81 | The options tt(--suspend) and tt(--rerun) (see section ref(ROTATE)) were | |
82 | implemented to allow safe rotations of s()'s report file. | |
83 | ||
84 | COMMENT( | |
85 | ||
86 | This second was removed since the distributions are responsible for | |
87 | archive integrity | |
88 | ||
89 | subsect(The integrity of the stealth distribution) | |
90 | ||
91 | The integrity of the archive tt(stealth-_CurVers_.tar.gz) can be verified as | |
92 | follows: | |
93 | itemization( | |
94 | it() At the location where you found this archive, you should also find a | |
95 | file named tt(stealth-_CurVers_.dsc). This file contains a PGP signed | |
96 | bf(sha1sum)(1) signature of the tt(tar.gz) archive. The PGP signature was | |
97 | provided by me using bf(gpg)(1) (bf(pgp)(1)). | |
98 | it() Compute the SHA1 checksum of the tt(stealth-_CurVers_.tar.gz) | |
99 | archive. Its value should match the SHA1 checksum that is mentioned in the | |
100 | tt(stealth-_CurVers_.dsc) file. If not, the tt(stealth-_CurVers_.tar.gz) | |
101 | archive has been compromised, and should em(not) be used. | |
102 | it() In order to verify the validity of the electronic signature, do as | |
103 | follows: | |
104 | itemization( | |
105 | it() Obtain my public key from a public PGP keyserver, e.g. | |
106 | verb( http://pgp.surfnet.nl:11371/) | |
107 | it() Make sure you have the right key. Its fingerprint is | |
108 | verb( DF32 13DE B156 7732 E65E 3B4D 7DB2 A8BE EAE4 D8AA) | |
109 | and it has been electronically signed by, e.g., the University of | |
110 | Groningen's PGP-certificate authority. If in doubt, contact me to verify you | |
111 | have the right key. | |
112 | it() Once you're sufficiently satisfied that you indeed have obtained | |
113 | my public PGP key, verify the validity of the signature used for signing | |
114 | tt(stealth-_CurVers_.dsc). With bf(gpg)(1) this can be done by the command | |
115 | verb( gpg --verify stealth-_CurVers_.dsc) | |
116 | ) | |
117 | ) | |
118 | This should produce output comparable to: | |
119 | verb(gpg: Signature made Fri Jun 1 10:57:41 2012 CEST using DSA key ID EAE4D8AA | |
120 | gpg: Good signature from "Frank B. Brokken <f.b.brokken@rug.nl>") | |
121 | ||
122 | END COMMENT) | |
114 | The options tt(--suspend) and tt(--resume) (see section ref(ROTATE)) were | |
115 | implemented to allow safe rotations of s()'s log-files. | |
123 | 116 | |
124 | 117 | |
125 | 118 | |
130 | 123 | |
131 | 124 | |
132 | 125 | |
126 |
9 | 9 | it() Inspect, and where necessary modify the values of the variables in |
10 | 10 | the files tt(INSTALL.cf) and tt(icmconf); |
11 | 11 | it() Install a recent Gnu tt(g++) compiler; |
12 | it() Install the bobcat library | |
12 | it() Install the bobcat library (both the binary and development version) | |
13 | 13 | (lurl(http://bobcat.sourceforge.net)); |
14 | 14 | it() Install the tt(icmake) program |
15 | 15 | (lurl(http://icmake.sourceforge.net)); |
0 | 0 | S() uses a policy file consisting of two sections, the second |
1 | section is optional. | |
1 | section is optional, and starts at a line merely containing tt(%%). | |
2 | ||
3 | Each policy file is uniquely associated with a host to be tested. Each host | |
4 | may have multiple policy files, though. In that case, each policy file defines | |
5 | its own set of checks to be performed. | |
2 | 6 | |
3 | 7 | itemization( |
4 | it() The policy file's first section defines the actions that s() must | |
5 | perform. Each policy file is uniquely associated with a host to be | |
6 | tested. Each host may have multiple policy files, though. In that case, each | |
7 | policy file defines its own set of checks to be performed. | |
8 | it() The policy file's first section consists of two sets of data: em(use | |
9 | directives) (starting with the keyword bf(USE)) and em(commands). | |
8 | 10 | |
9 | it() The policy file's optional second section starts with a line merely | |
10 | containing tt(%%), which may then be followed by certain long option | |
11 | specifications. See section ref(OPTIONS) for an overview. | |
11 | it() The (optional) second section starts at a line merely containing | |
12 | tt(%%). Following this separating line several long option specifications can | |
13 | be entered (cf. section ref(OPTIONS)). Options | |
14 | specified on the command-line take priority over options specified | |
15 | in the policy file. Although the tt(--reload) option reloads the policy file, | |
16 | it will not change option values originally specified as command-line options. | |
17 | ||
18 | This section may contain specifications of the tt(skip-files) and tt(log) | |
19 | options. Relative file locations specified for these options are interpreted | |
20 | relative to the location of the policy file. E.g., if the policy file argument | |
21 | is specified as tt(/root/client/policy) then the specification tt(log: | |
22 | client.log) results in s() writing its logs into the file | |
23 | tt(/root/client/client.log). | |
12 | 24 | ) |
13 | 25 | |
14 | In this chapter the term em(controller) is used for the computer running | |
15 | s(), while the term em(client) is used for the computer that is scanned by | |
16 | s(). The controller and the client could be the same computer, but | |
17 | normally they are different. | |
18 | 26 | |
19 | 27 | The policy file's first section consists of three sets of data: em(define |
20 | 28 | directives) (starting with the keyword bf(DEFINE)), em(use directives) |
21 | 29 | (starting with the keyword bf(USE)) and em(commands). |
22 | 30 | |
23 | 31 | Directives are written in capitals, and should appear exactly as written |
24 | below; letter casing is preserved. | |
32 | below. | |
25 | 33 | |
26 | 34 | Blank lines and information beyond hash-marks (#) are ignored, while lines |
27 | 35 | following lines terminating in backslashes (\ ) will be concatenated (em(en |
28 | passant) removing these backslashes). Initial white space on lines of the | |
36 | passant) removing these backslashes). Leading white space on lines of the | |
29 | 37 | policy file is ignored. |
30 | 38 | |
39 |
16 | 16 | ) |
17 | 17 | |
18 | 18 | Examples: |
19 | verb( LABEL Inspecting files in /etc\nIncluding subdirectories | |
19 | verb( | |
20 | LABEL Inspecting files in /etc\nIncluding subdirectories | |
20 | 21 | LABEL) |
21 | The second bf(LABEL) command clears the first label. | |
22 | The latter bf(LABEL) command clears the text of the former bf(LABEL) | |
23 | command. |
0 | 0 | bf(LOCAL) commands can be used to specify commands that are |
1 | executed on the controller itself. The following bf(LOCAL) commands are | |
1 | executed on the monitor itself. The following bf(LOCAL) commands are | |
2 | 2 | available: |
3 | 3 | itemization( |
4 | 4 | it() bf(LOCAL) tt(command) |
5 | 5 | |
6 | Execute tt(command) on the controller, using the bf(SH) command | |
6 | Execute tt(command) on the monitor, using the bf(SH) command | |
7 | 7 | shell. The command must succeed (i.e., must return a zero exit value). |
8 | 8 | Example: |
9 | 9 | verb( LOCAL mkdir /tmp/client) |
10 | This command creates the directory tt(/tmp/client) on the controller. | |
10 | This command creates the directory tt(/tmp/client) on the monitor. | |
11 | 11 | |
12 | 12 | it() bf(LOCAL NOTEST) tt(command) |
13 | 13 | |
14 | Execute tt(command) on the controller, using the bf(SH) command | |
14 | Execute tt(command) on the monitor, using the bf(SH) command | |
15 | 15 | shell. The command may or may not succeed. |
16 | 16 | Example: |
17 | 17 | verb( LOCAL NOTEST mkdir /tmp/subdir) |
18 | This command creates tt(/tmp/subdir) on the controller. The command | |
18 | This command creates tt(/tmp/subdir) on the monitor. The command | |
19 | 19 | fails if the directory cannot be created, but this does not terminate |
20 | 20 | s(). |
21 | 21 | |
22 | 22 | it() bf(LOCAL CHECK) [bf(LOG =)] tt(logfile [pathOffset] command) |
23 | 23 | |
24 | Execute tt(command) on the controller, using the bf(SH) command shell. | |
25 | The phrase `bf(LOG =)' is optional. | |
24 | Execute tt(command) on the monitor, using the bf(SH) command | |
25 | shell. The command must succeed. The output of this command is compared to the | |
26 | output of this command generated during the previous integrity check run by | |
27 | s(). | |
26 | 28 | |
27 | The tt([pathOffset]) is also optional. If specified it defines the (0-based) | |
28 | offset where path-names of inspected files start in lines produced by the | |
29 | diff-command, comparing the previous report and the output generated by | |
30 | tt(<command>). By default s() assumes that the first occurrence of a | |
31 | forward slash defines the first character of the path-names of inspected | |
32 | files. | |
29 | The phrase bf(LOG =) is optional. When a relative file location is | |
30 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
31 | path specification. | |
32 | ||
33 | tt(PathOffset) is also optional. If specified it defines the (0-based) | |
34 | offset where path-names of inspected files start in lines produced by | |
35 | tt(<command>). By default s() assumes that the first occurrence of a forward | |
36 | slash defines the first character of the path-names of inspected files. | |
33 | 37 | |
34 | 38 | For example, if diff-output looks like this: |
35 | verb( 01234567890123456789012345678901234567890 (column offsets, not part of | |
39 | verb( | |
40 | 01234567890123456789012345678901234567890 (column offsets, not part of | |
36 | 41 | the diff-output) |
37 | 42 | |
38 | 43 | 33c33 |
51 | 56 | forged: |
52 | 57 | verb( *** BE CAREFUL *** REMAINING RESULTS MAY BE FORGED) |
53 | 58 | This situation may occur, e.g., if an essential program (like tt(sha1sum)) |
54 | was transferred to the controller, and it was apparently modified since the | |
59 | was transferred to the monitor, and it was apparently modified since the | |
55 | 60 | previous check. Processing continues, but remaining checks performed at the |
56 | 61 | client computer should be interpreted with em(extreme) caution. |
57 | 62 | |
64 | 69 | the time s() was run. |
65 | 70 | |
66 | 71 | Over time, many tt(logfile.YYMMDD-HHMMSS) files could be accumulated. |
67 | It is up to the controller's systems manager to decide what to do | |
72 | It is up to the monitor's systems manager to decide what to do | |
68 | 73 | with old datetime-stamped logfiles. For instance, the following script |
69 | 74 | removes all s() reports below the current directory that are |
70 | 75 | older than 30 days: |
88 | 93 | |
89 | 94 | it() bf(LOCAL NOTEST CHECK) [bf(LOG =)] tt(logfile [pathOffset] command) |
90 | 95 | |
91 | Execute tt(command) on the controller, using the bf(SH) command | |
92 | shell. The phrase `bf(LOG =)' is optional. The command may or may not | |
93 | succeed. Otherwise, the program performs exactly like the bf(LOCAL CHECK ...) | |
94 | command, discussed above. | |
96 | Execute tt(command) on the monitor, using the bf(SH) command | |
97 | shell. | |
98 | ||
99 | The phrase bf(LOG =) is optional. When a relative file location is | |
100 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
101 | path specification. | |
102 | ||
103 | The command may or may not succeed. Otherwise, the program performs exactly | |
104 | like the bf(LOCAL CHECK ...) command, discussed above. | |
95 | 105 | |
96 | 106 | Example: |
97 | 107 | verb( LOCAL NOTEST CHECK LOG=local/sha1sum sha1sum /tmp/sha1sum) |
0 | Either by malicious intent or by accident (as happened to me) the controller | |
1 | may be a victim of a Denial of Service (DOS) attack. This DOS attack may occur | |
2 | when the client (apparently) sends a never ending stream of bytes in response | |
3 | to a tt(GET) or tt(REMOTE) command. Once one of my controllers fell victim to | |
4 | this attack when a client's power went down and the controller kept on trying | |
5 | to read bytes from that client filling up the controller's disk.... | |
0 | Either by malicious intent or by accident (as happened to me) the monitor may | |
1 | be a victim of a (self-inflicted) Denial of Service (DOS) attack. This DOS | |
2 | attack may occur when the client (apparently) sends a never ending stream of | |
3 | bytes in response to a tt(GET) or tt(REMOTE) command. Once one of my monitors | |
4 | fell victim to this attack when a client's power went down and the monitor | |
5 | kept on trying to read bytes from that client filling up the monitor's | |
6 | disk.... | |
6 | 7 | |
7 | 8 | This problem was of course caused by a programming error: while reading |
8 | 9 | information from a client s() failed to check whether the reading had actually |
13 | 14 | ending stream of bytes to be written to its `report' file, thus causing its |
14 | 15 | disk to fill up. |
15 | 16 | |
16 | To prevent this from happening s() offers the tt(--max-size) | |
17 | To prevent this from happening s() now offers the tt(--max-size) | |
17 | 18 | command line option allowing the specification of the maximum size of a stream |
18 | 19 | of bytes received by s() (e.g., a report or downloaded file). The |
19 | 20 | maximum is used for each individual download and can be specified in bytes |
24 | 25 | If a file or report received from the client exceeds its maximum allowed size |
25 | 26 | then s() terminates after writing the following message to the report |
26 | 27 | file (which is sent to the configured mail address): |
27 | verb( STEALTH - CAN'T CONTINUE: `<name of offending file>' EXCEEDS MAX. | |
28 | verb( | |
29 | STEALTH - CAN'T CONTINUE: `<name of offending file>' EXCEEDS MAX. | |
28 | 30 | DOWNLOAD SIZE (<size shown>) |
29 | 31 | STEALTH - THIS COULD SIGNAL A SERIOUS PROBLEM WITH THE CLIENT |
30 | 32 | STEALTH - ONE OR MORE LOG FILES MAY BE INVALID AS A RESULT |
12 | 12 | intended program. |
13 | 13 | |
14 | 14 | Two special remote commands are tt(GET) and tt(PUT), which can be used to |
15 | copy files between the client and the controller. Internally, tt(GET) and | |
15 | copy files between the client and the monitor. Internally, tt(GET) and | |
16 | 16 | tt(PUT) use the tt(DD) use-specification. If a non-default specification is |
17 | 17 | used, one should ensure that the alternate program accepts bf(dd)(1)'s tt(if=, |
18 | 18 | of=, bs=) and tt(count=) options. With tt(GET) the options tt(bs=, count=) and |
24 | 24 | startit() |
25 | 25 | it() bf(GET) tt(<client-path> <local-path>)nl() |
26 | 26 | Copy the file indicated by tt(client-path) at the client to tt(local-path) |
27 | at the controller. tt(client-path) must be the full path of an existing file | |
27 | at the monitor. tt(client-path) must be the full path of an existing file | |
28 | 28 | on the client, tt(local-path) may either be a local directory, in which case |
29 | 29 | the client's file name is used, or another file name may be specified, in |
30 | 30 | which case the client's file is copied to the specified local filename. If the |
33 | 33 | Example: |
34 | 34 | verb( GET /usr/bin/sha1sum /tmp) |
35 | 35 | The program tt(/usr/bin/sha1sum), available at the client, is copied to |
36 | the controller's tt(/tmp) directory. If copying fails for some reason, any | |
36 | the monitor's tt(/tmp) directory. If copying fails for some reason, any | |
37 | 37 | subsequent commands are skipped, and s() terminates. |
38 | 38 | |
39 | 39 | it() bf(GET NOTEST) tt(<client-path> <local-path>)nl() |
40 | 40 | Copy the file indicated by tt(client-path) at the client to tt(local-path) |
41 | at the controller. tt(client-path) must be the full path of an existing file | |
41 | at the monitor. tt(client-path) must be the full path of an existing file | |
42 | 42 | on the client, tt(local-path) may either be a local directory, in which case |
43 | 43 | the client's file name is used, or another file name may be specified, in |
44 | 44 | which case the client's file is copied to the specified local filename. If the |
47 | 47 | Example: |
48 | 48 | verb( GET NOTEST /usr/bin/sha1sum /tmp) |
49 | 49 | The program tt(/usr/bin/sha1sum), available at the client, is copied to the |
50 | controller's tt(/tmp) directory. Remaining commands in the policy file are | |
50 | monitor's tt(/tmp) directory. Remaining commands in the policy file are | |
51 | 51 | executed, even if the copying process wasn't successful. |
52 | 52 | endit() |
53 | 53 | |
54 | 54 | The tt(PUT) command may be used as follows: |
55 | 55 | startit() |
56 | 56 | it() bf(PUT) tt(<local-path> <remote-path>)nl() |
57 | Copy the file indicated by tt(local-path) at the controller to | |
57 | Copy the file indicated by tt(local-path) at the monitor to | |
58 | 58 | tt(remote-path) at the client. The argument tt(local-path) must be the |
59 | full path of an existing file on the controller. The argument tt(remote-path) | |
59 | full path of an existing file on the monitor. The argument tt(remote-path) | |
60 | 60 | must be the full path to a file on the client. If the remote file already |
61 | 61 | exists, it is overwritten by tt(PUT). |
62 | 62 | |
63 | 63 | Example: |
64 | 64 | verb( PUT /tmp/sha1sum /usr/bin/sha1sum) |
65 | The program tt(/tmp/sha1sum), available at the controller, is copied to the | |
65 | The program tt(/tmp/sha1sum), available at the monitor, is copied to the | |
66 | 66 | client as tt(usr/bin/sha1sum). If the copying fails for some reason, |
67 | 67 | any subsequent commands are skipped, and s() terminates. |
68 | 68 | |
69 | 69 | it() bf(PUT NOTEST) tt(<local-path> <remote-path>)nl() |
70 | Copy the file indicated by tt(local-path) at the controller to | |
70 | Copy the file indicated by tt(local-path) at the monitor to | |
71 | 71 | tt(remote-path) at the client. The argument tt(local-path) must be the |
72 | full path of an existing file on the controller. The argument tt(remote-path) | |
72 | full path of an existing file on the monitor. The argument tt(remote-path) | |
73 | 73 | must be the full path to a file on the client. If the remote file already |
74 | 74 | exists, it is overwritten by tt(PUT). |
75 | 75 | |
76 | 76 | Example: |
77 | 77 | verb( PUT NOTEST /tmp/sha1sum /usr/bin/sha1sum) |
78 | Copy the file indicated by tt(local-path) at the controller to | |
78 | Copy the file indicated by tt(local-path) at the monitor to | |
79 | 79 | tt(remote-path) at the client. The argument tt(local-path) must be the full |
80 | path of an existing file on the controller. The argument tt(remote-path) must | |
80 | path of an existing file on the monitor. The argument tt(remote-path) must | |
81 | 81 | be the full path to a file on the client. If the remote file already exists, |
82 | 82 | it is overwritten by tt(PUT). Remaining commands in the policy file are |
83 | 83 | executed, even if the copying process wasn't successful. |
109 | 109 | it() bf(CHECK) [bf(LOG =)] tt(logfile [pathOffset] command) |
110 | 110 | |
111 | 111 | Execute tt(command) on the client, using the bf(SSH) command |
112 | shell. The phrase `bf(LOG =)' is optional. The tt([pathOffset]) specification | |
113 | is also optional, and has the same meaning as for the tt(LOCAL CHECK) command, | |
114 | described above. | |
112 | shell. | |
113 | ||
114 | The phrase bf(LOG =) is optional. When a relative file location is | |
115 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
116 | path specification. | |
117 | ||
118 | tt(PathOffset) is also optional, and has the same meaning as for the tt(LOCAL | |
119 | CHECK) command, described above. | |
115 | 120 | |
116 | 121 | The command must succeed. The output of this command is compared to the |
117 | 122 | output of this command generated during the previous run of s(). Any |
120 | 125 | tt(YYYYMMDD-HHMMSS) being the datetime-stamp at the time s() was run. |
121 | 126 | |
122 | 127 | Note that the command is executed on the client, but the logfile is kept |
123 | at the controller. This command represents the core of the method implemented | |
128 | at the monitor. This command represents the core of the method implemented | |
124 | 129 | by s(): there will be no residues of the actions performed by s() on client |
125 | 130 | computers. |
126 | 131 | |
148 | 153 | it() bf(NOTEST CHECK) [bf(LOG =)] tt(logfile [pathOffset] command) |
149 | 154 | |
150 | 155 | Execute tt(command) on the client, using the bf(SSH) command |
151 | shell. The phrase `bf(LOG =)' is optional. The tt([pathOffset]) is also | |
152 | optional, and has the same meaning as for the tt(LOCAL CHECK) command, | |
153 | described above. The command may or may not succeed. Otherwise, the program | |
154 | acts identically as the bf(CHECK ...) command, described above. | |
156 | shell. | |
157 | ||
158 | The phrase bf(LOG =) is optional. When a relative file location is | |
159 | specified at tt(<file-spec>) it is interpreted relatively to the tt(USE BASE) | |
160 | path specification. | |
161 | ||
162 | tt(PathOffset) is also optional, and has the same meaning as for the tt(LOCAL | |
163 | CHECK) command, described above. The command may or may not | |
164 | succeed. Otherwise, the program acts identically as the bf(CHECK ...) command, | |
165 | described above. | |
155 | 166 | Example (using the same tt(${SHA1SUM}))definition: |
156 | 167 | verb( NOTEST CHECK LOG = remote/sha1.root /usr/bin/find / ${SHA1SUM}) |
157 | 168 | The SHA1 checksums of all suid/gid/executable files on the same device as |
3 | 3 | itemization( |
4 | 4 | it() bf(USE BASE) tt(basedirectory) |
5 | 5 | |
6 | bf(BASE) defines the directory from where s() operates. All | |
7 | relative path specifications are interpreted relative to bf(BASE). em(By | |
8 | default) this is the directory where s() was started. | |
6 | bf(BASE) defines the directory from where s() operates. All relative | |
7 | path specifications in this section of the policy file are interpreted | |
8 | relative to bf(BASE). em(By default) this is the directory where s() was | |
9 | started. | |
9 | 10 | |
10 | 11 | If necessary, s() creates all bf(BASE) and other directories below |
11 | 12 | tt(BASE). |
18 | 19 | it() bf(USE DD) tt(<dd>)nl() |
19 | 20 | The bf(DD) specification uses tt(/bin/dd) as default, and defines the |
20 | 21 | location of the bf(dd)(1) program, both on the server and on the client. The |
21 | bf(DD) program is used to copy files between the client and the controller | |
22 | bf(DD) program is used to copy files between the client and the monitor | |
22 | 23 | without creating separate ssh-connections. The bf(DD) program is only |
23 | 24 | used by s() for the tt(PUT) and tt(GET) commands, described below. |
24 | 25 | |
89 | 90 | taken as a string, and the information beyond the first string is thereupon |
90 | 91 | interpreted. |
91 | 92 | |
92 | it() bf(USE REPORT) tt(reportfile) | |
93 | it() bf(USE REPORT) tt(<file-spec>)nl() | |
94 | bf(REPORT) defines the name of the reportfile. Information is always | |
95 | appended to this file. At each s() integrity scan a em(time marker line) is | |
96 | written to the report file. Only when (in addition to the marker line) | |
97 | additional information is appended to the report file the added contents of | |
98 | the report file are mailed to the mail address specified in the bf(USE EMAIL) | |
99 | specification. When a relative file specification is used it is interpreted a | |
100 | location relative to the tt(USE BASE) specification.nl() | |
101 | Example showing the default:nl() | |
102 | tt(USE REPORT report) | |
93 | 103 | |
94 | bf(REPORT) defines the name of the reportfile. Information is always | |
95 | appended to this file. For each s() run a em(time marker line) is | |
96 | written to the report file. Such a marker line looks like this: | |
97 | verb( STEALTH (1.11) started at Mon Jun 16 12:57:26 2003) | |
98 | Only when (in addition to the marker line) | |
99 | additional information was appended to the report file, the added contents of | |
100 | the report file are mailed to the mail address specified in the bf(USE EMAIL) | |
101 | specification. | |
104 | it() bf(USE SH) tt(<sh>)nl() | |
105 | The bf(SH) specification uses tt(/bin/sh) as default, and defines the | |
106 | command shell used by the monitor to execute commands on itself. This must be | |
107 | an absolute path specification.nl() | |
108 | Example showing the default:nl() | |
109 | tt(USE SH /bin/sh) | |
102 | 110 | |
103 | Example showing the default: | |
104 | verb( USE REPORT report) | |
111 | it() bf(USE SSH) tt(<user>)nl() | |
112 | bf(The SSH specification has no default), and em(must) be | |
113 | specified. This must be an absolute path specification. | |
105 | 114 | |
106 | it() bf(USE SH) tt(sh-specification) | |
115 | Assuming the client em(trusts) the monitor (which is after all what this | |
116 | program is all about, so this should not be a very strong assumption), | |
117 | preferably the public ssh key of the monitor should be placed in the | |
118 | client's root tt(.ssh/authorized_keys) file, granting the monitor root access | |
119 | to the client. Root access is normally needed to gain access to all | |
120 | directories and files of the client's file system. | |
107 | 121 | |
108 | The bf(SH) specification uses tt(/bin/sh) as default, and defines the | |
109 | command shell used by the controller to execute local commands. | |
110 | ||
111 | Example showing the default: | |
112 | verb( USE SH /bin/sh) | |
113 | ||
114 | it() bf(USE SSH) tt(ssh-specification) | |
115 | ||
116 | bf(The SSH specification has no default), and em(must) be | |
117 | specified. Assuming the client em(trusts) the controller (which is, after all, | |
118 | what this program is all about; so this should not be a very strong | |
119 | assumption), preferably the public ssh-identity key of the controller should | |
120 | be placed in the client's root tt(.ssh/authorized_keys) file, granting the | |
121 | controller root access to the client. Root access is normally needed to gain | |
122 | access to all directories and files of the client's file system. | |
123 | ||
124 | In practice, connecting to a account using the bf(sh)(1) shell is | |
122 | In practice, connecting to an account using the bf(sh)(1) shell is | |
125 | 123 | preferred. When another shell is already used by that account, one should make |
126 | sure that that shell doesn't setup its own redirections for standard input and | |
127 | standard output. One way to accomplish that is for force the execution of | |
128 | tt(/bin/sh) in the bf(USE SSH) specification. | |
124 | sure that its shell doesn't define its own redirections for standard input | |
125 | and standard output. One way to accomplish that is for force the execution of | |
126 | tt(/bin/sh) in the bf(USE SSH) specification. | |
129 | 127 | |
130 | 128 | An example of an tt(SSH) specification to scan a localhost is: |
131 | verb( USE SSH root@localhost -T -q # root's shell is /bin/sh) | |
129 | verb( | |
130 | USE SSH root@localhost -T -q # root's shell is /bin/sh) | |
132 | 131 | |
133 | 132 | The same, now explicitly using tt(/bin/bash): |
134 | verb( USE SSH root@localhost -T -q exec /bin/bash # root uses another shell) | |
133 | verb( | |
134 | USE SSH root@localhost -T -q exec /bin/bash # root uses another shell) | |
135 | 135 | |
136 | 136 | Alternatively, tt(--noprofile) can be specified to prevent any |
137 | 137 | profile-initialization: |
138 | verb( USE SSH root@localhost -T -q exec /bin/bash --noprofile) | |
138 | verb( | |
139 | USE SSH root@localhost -T -q exec /bin/bash --noprofile) | |
139 | 140 | ) |
140 | Using tt(stealth) to inspect tt(localhost) is em(not) | |
141 | recommended, as it counters one of the main reasons for tt(stealth)'s | |
142 | existence. | |
143 | 141 | |
144 | itemization( | |
145 | it() Yet another alternative, applicable only to tt(localhost). tt(Ssh) | |
146 | could completely be avoided, specifying tt(/bin/bash) or a comparable shell | |
147 | with the tt(USE SSH) directive. For example: | |
142 | In some installations s() is used to inspect the monitor itself, even | |
143 | though this is em(not) recommended, as it breaks one of the main reasons for | |
144 | s()'s existence. But in those situations (so, where s() is used to monitor the | |
145 | integrity of the tt(localhost)), tt(/bin/bash) could be specified at the | |
146 | tt(USE SSH) directive. For example: | |
148 | 147 | verb( # For stealth inspecting localhost: |
149 | 148 | USE SSH /bin/bash --noprofile) |
150 | ) |
0 | Next, we check the received tt(sha1sum) program, using our own: | |
0 | Next, we check the integrity of the received tt(sha1sum) program. For this, we | |
1 | use the monitor's tt(sha1sum) program: | |
1 | 2 | verb( |
2 | 3 | LABEL \nCheck the client's sha1sum program |
3 | 4 | LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum |
9 | 10 | client. The report is written on the file |
10 | 11 | tt(/root/stealth/client/local/sha1). If this fails, s() terminates, alerting |
11 | 12 | tt(admin@elsewhere) that the check failed. This is a serious event, as it |
12 | indicates that either the controller's tt(sha1sum) is behaving unexpectedly or | |
13 | indicates that either the monitor's tt(sha1sum) is behaving unexpectedly or | |
13 | 14 | that the client's tt(sha1sum) program has unexpectedly changed. |
14 | 15 | |
15 | 16 | The tt(sha1sum) program em(may) have changed due to a normal upgrade. If |
4 | 4 | know that the client's tt(sha1sum) program is OK, we can use it to check the |
5 | 5 | client's tt(/usr/bin/find) program. |
6 | 6 | |
7 | Note that the controller itself will not suffer any processing load here: only | |
8 | the client itself is taxed for checking the intergrity of its own files: | |
9 | verb( LABEL \nchecking the client's /usr/bin/find program | |
7 | Note that the monitor itself no longer needs to invest any significant | |
8 | processing load: only the client itself is taxed for checking the integrity | |
9 | of its own files: | |
10 | verb( | |
11 | LABEL \nchecking the client's /usr/bin/find program | |
10 | 12 | CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find) |
11 | 13 |
2 | 2 | client. For this we activate the tt(sha1sum) program on the client. In |
3 | 3 | order to check the setuid/setgid files, the following command is added to the |
4 | 4 | policy file: |
5 | verb( LABEL \nsuid/sgid/executable files uid or gid root on the / partition | |
5 | verb( | |
6 | LABEL \nsuid/sgid/executable files uid or gid root on the / partition | |
6 | 7 | CHECK LOG = remote/setuidgid /usr/bin/find / ${EXECSHA1}) |
7 | 8 |
0 | First, we copy the client's tt(sha1sum) program to the controller. In | |
0 | The following commands are now defined: | |
1 | itemization( | |
2 | it() first, we copy the client's tt(sha1sum) program to the monitor. In | |
1 | 3 | practice, this should also include the shared object libraries that are used |
2 | by tt(sha1sum), as they might have become corrupted as well. | |
4 | by tt(sha1sum), as they might have become corrupted as well; | |
5 | it() Once tt(sha1sum) is locally available its integrity is verified; | |
6 | it() Once the integrity of the client's tt(sha1sum) has been verified, it | |
7 | is used to verify the integrity of the client's tt(/usr/bin/find) program; | |
8 | it() Following this, all setuid and setgid root files are located and | |
9 | checked for integrity; | |
10 | it() Finally, the integrity of the client configuration files under | |
11 | tt(/etc) is verified; | |
12 | ) | |
3 | 13 | |
14 | In this manual the bf(sha1sum)(1) program is frequently used when checking | |
15 | hash values. Stronger hash functions (like bf(sha256sum)(1) might be preferred | |
16 | in practice. tt(sha256sum's) hash values are remarkably longer than | |
17 | tt(sha1sum's) hash values. When using these longer hash values in the manual | |
18 | it often clobbers the layout of examples. Therefore in this manual | |
19 | bf(sha1sum)(1) is continued to be used. | |
20 | ||
21 | Realize, however, that when updating existing policy files to use | |
22 | bf(sha256sum)(1) instead of bf(sha1sum)(1), that previously generated log | |
23 | files (that used bf(sha1sum)(1)) are incompatible with log files obtained when | |
24 | using bf(sha256sum)(1). In practice this means that new log files need to be | |
25 | generated, and any previously geneerated log files must be disregarded. | |
26 |
1 | 1 | tt(/etc/cron.d/stealth) could be created, containing a line like |
2 | 2 | verb( |
3 | 3 | 2,17,32,47 * * * * root test -x /usr/bin/stealth && \ |
4 | /usr/bin/stealth -q /root/stealth/client.pol | |
4 | /usr/bin/stealth /root/stealth/client.pol | |
5 | 5 | ) |
6 | 6 | This starts s() 2 minutes after every hour. In this example the ssh-key |
7 | 7 | must not require a passphrase, as bf(crontab)(1) cannot provide passphrases of |
17 | 17 | option. For example, the s() daemon started by the following command |
18 | 18 | repeatedly performs integrity scans between two and five minutes after the |
19 | 19 | last integrity scan completed: |
20 | verb( stealth -d /var/run/client.pid -r 2m -i 3m /root/stealth/client.pol) | |
20 | verb( | |
21 | stealth --daemon /root/stealth/client.uds \ | |
22 | --repeat 2m --random-interval 3m /root/stealth/client.pol) | |
23 | Once this program has started its bf(ssh)(1) connection to the client host | |
24 | persists, and a possibly required ssh-passphrase is no longer | |
25 | required. Additional (intermediate) integrity scans can always be requested | |
26 | (also without requiring ssh-passphrase specifications) using the command | |
27 | verb( | |
28 | stealth --rerun /root/stealth/client.uds) | |
29 |
0 | 0 | First we write some tt(DEFINE) directives simplifying complex command |
1 | 1 | specifications: |
2 | verb( DEFINE SSHCMD /usr/bin/ssh root@client -T -q exec /bin/bash --noprofile | |
2 | verb( | |
3 | DEFINE SSHCMD /usr/bin/ssh root@client -T -q exec /bin/bash --noprofile | |
3 | 4 | DEFINE EXECSHA1 -xdev -perm +u+s,g+s \( -user root -or -group root \) \ |
4 | 5 | -type f -exec /usr/bin/sha1sum {} \;) |
5 | 6 | The first tt(DEFINE) defines the tt(ssh) command to use: an ssh-connection |
1 | 1 | has developed. In that case, further actions by s() would be suspect, as their |
2 | 2 | results might easily be currupted. Additional checks em(will) be performed, |
3 | 3 | but a warning is generated on the tt(report) file (and in the mail sent to |
4 | tt(admin@elsewhere): | |
5 | verb( STEALTH (3.00.00) started at Wed, 20 Aug 2014 11:13:38 +0000 | |
4 | tt(admin@elsewhere)): | |
5 | verb( | |
6 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:27:15 +0100 | |
6 | 7 | |
7 | 8 | Check the client's sha1sum program |
8 | 9 | MODIFIED: /root/tmp/sha1sum |
47 | 47 | |
48 | 48 | it() The file tt(/root/client/report) bf(New lines are always appended to |
49 | 49 | the tt(/root/client/report) file. It will never shorten, unless shorten by |
50 | the systems administrator at `controller'). | |
50 | the systems administrator at `monitor'). | |
51 | 51 | |
52 | 52 | This file contains the following: |
53 | 53 | verb( STEALTH (3.00.00) started at Wed, 20 Aug 2014 11:06:50 +0000 |
0 | 0 | As s() is mainly a system administrator's tool, it could be |
1 | installed in tt(/usr/bin). In that case, do (as em(root)) from the | |
1 | installed in tt(/usr/bin). In that case, do (as em(root)) in the | |
2 | 2 | directory where s() was compiled/unpacked: |
3 | 3 | verb( ./build install program) |
4 | 4 | Alternatively, another default location may be specified in the |
6 | 6 | verb( ./build install program /usr/local/bin/stealth) |
7 | 7 | installing the binary program as tt(/usr/local/bin/stealth). |
8 | 8 | |
9 | The provided tt(icmake build) script can be started without arguments for an | |
10 | overview of possible commands. | |
11 | ||
12 |
5 | 5 | bf(logrotate)(1). Logrotate (on Debian systems) keeps its configuration files |
6 | 6 | in tt(/etc/logrotate.d), and assuming there is a host tt(target), whose report |
7 | 7 | file is tt(/var/stealth/target/report), the required bf(logrotate)(1) |
8 | specification file (e.g., tt(/etc/logrotate.d/target) could be: | |
8 | specification file (e.g., tt(/etc/logrotate.d/target)) could be: | |
9 | 9 | verbinclude(../../../share/etc/logrotate.d/target) |
10 | 10 | Using this specification file, bf(logrotate)(1) will |
11 | 11 | itemization( |
12 | 12 | it() perform weekly rotations of the report file; |
13 | 13 | it() keep up to 12 rotated files, compressing them using bf(gzip)(1); |
14 | 14 | it() suspend the s() daemon, before rotating its report file; |
15 | suppressed; | |
15 | suspended; | |
16 | 16 | it() following the rotation, s()'s actions are resumed. |
17 | 17 | ) |
18 | 18 | Note thet tt(stealth --resume xxx) always initiates another file integrity |
0 | 0 | The tt(/root/bin/stealthmail) script is called with the following arguments: |
1 | verb( "Client STEALTH report" admin@elswhere) | |
1 | verb( | |
2 | "Client STEALTH report" admin@elswhere) | |
2 | 3 | |
3 | 4 | The mailed report contains information comparable to this: |
4 | verb( STEALTH (3.00.00) started at Wed, 20 Aug 2014 11:06:50 +0000 | |
5 | verb( | |
6 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:10:56 +0100 | |
5 | 7 | |
6 | 8 | Check the client's sha1sum program |
7 | 9 | Initialized report on local/sha1 |
1 | 1 | store information about the host tt(client) under the subdirectory |
2 | 2 | tt(/root/stealth/client). |
3 | 3 | |
4 | Stealth reports should be sent to the user tt(admin@elsewhere), who is only | |
5 | interested in a short notice of changes, as the full report can always be read | |
6 | elsewhere. For this a support-script was developed filtering the report | |
7 | generated by s() down to its essentials. | |
4 | Furthermore, we assume that reports of s() integrity-scans should be sent to | |
5 | the user tt(admin@elsewhere), who is only interested in receiving a short | |
6 | summary of changes, as the full report can always be read at the monitor | |
7 | itself. To accomplish this a small support-script was developed, filtering the | |
8 | report generated by s() down to its essentials. | |
8 | 9 | |
9 | 10 | As the tt(sha1sum) program on the client may be compromised, it is a good idea |
10 | to transfer the client's tt(sha1sum) program to the controller first, | |
11 | verifying the integrity of that program at the controller, before trusting it | |
12 | to compute the sha1sums of the client's files. The same holds true for any | |
13 | libraries and support programs (like tt(find)) that are used intensively | |
14 | during integrity scans. | |
11 | to start the integrity scan by transferring the client's tt(sha1sum) program | |
12 | to the monitor first, to verify the integrity of that program locally (i.e., | |
13 | at the monitor), before trusting it to compute sha1sums of the client's | |
14 | files. The same holds true for any libraries and support programs (like | |
15 | tt(find)) that are used intensively during integrity scans. | |
15 | 16 | |
16 | 17 | Sha1sum checks should be performed on all setuid and setgid files on the |
17 | 18 | tt(client), and in order to be able reach all files on tt(client), |
18 | tt(root@controller) is allowed to login to the tt(root@client) account using | |
19 | tt(root@monitor) is allowed to login to the tt(root@client) account using | |
19 | 20 | an tt(ssh) connection. |
20 | 21 | |
21 | 22 | Furthermore, sha1sum checks should be performed on all configuration files, |
22 | living under tt(/etc) and on the file tt(/usr/bin/find) which is used | |
23 | intensively to perform the checks. | |
23 | living under tt(/etc) and on the file tt(/usr/bin/find) (which is used | |
24 | intensively when performing the integrity checks). | |
24 | 25 | |
26 | Next, the construction of the required tt(policy) file, implementing the | |
27 | abovementioned requirements, is described in the following subsections. | |
25 | 28 | |
26 | The required tt(policy) file is now constructed according to the | |
27 | abovementioned requirements. | |
28 |
1 | 1 | tt(root/stealth/client). If nothing has changed, the log-files remain |
2 | 2 | unaltered. Subsequent runs will, however, add some new info to the file |
3 | 3 | tt(/root/client/report): |
4 | verb( STEALTH (3.00.00) started at Wed, 20 Aug 2014 11:06:50 +0000 | |
4 | verb( | |
5 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:10:56 +0100 | |
5 | 6 | |
6 | 7 | Check the client's sha1sum program |
7 | 8 | Initialized report on local/sha1 |
15 | 16 | configuration files under /etc |
16 | 17 | Initialized report on remote/etcfiles |
17 | 18 | |
18 | STEALTH (3.00.00) started at Wed, 20 Aug 2014 11:13:38 +0000) | |
19 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:22:15 +0100) | |
19 | 20 | Note that just one extra line was added: a timestamp showing the date/time |
20 | 21 | of the last run. The systems administrator may rotate the report file every |
21 | 22 | once in a while to reclaim some disk space. |
0 | First, the tt(sha1sum) program is copied to a local directory: | |
1 | verb( GET /usr/bin/sha1sum /root/tmp) | |
0 | To copy the client's tt(sha1sum) program to a local directory we specify: | |
1 | verb( | |
2 | GET /usr/bin/sha1sum /root/tmp) | |
2 | 3 | This command must succeed. |
3 | 4 |
0 | 0 | Short options are provided between parentheses, immediately following |
1 | their long option equivalents. Option descriptions starting with (C) can only | |
2 | be used on the command-line, and are ignored when specified in the second | |
3 | section of the policy file. | |
1 | their long option equivalents. | |
2 | ||
3 | Option descriptions showing (C) can only be used on the command-line, and | |
4 | are ignored when specified in the second section of the policy file. | |
5 | ||
6 | In the overview of options `tt(<uds>)' represents the name of the | |
7 | em(Unix Domain Socket) to use, and `tt(<file-spec>)' refers to a (relative or | |
8 | absolute) specification of a file location. | |
9 | ||
10 | With the first and second synopses relative locations (of the Unix Domain | |
11 | Socket and of other file-specifications) are interpreted relative to the | |
12 | current working directory. | |
13 | ||
14 | Command-line options overrule options defined in the policy-file. | |
4 | 15 | |
5 | 16 | itemization( |
6 | it() tt(--daemon (-d) <path>): (C) run as background (daemon) | |
7 | process. tt<path> specifies the absolute filename of the pid-file used | |
8 | for communication with the daemon process; | |
17 | it() tt(--daemon (-d) <uds>): (C) run as background (daemon) | |
18 | process. When the Stealth daemon process is started, the Unix Domain | |
19 | Socket (tt<uds>) may not already exist. | |
9 | 20 | it() tt(--dry-run): (C) no integrity scans or reloads are performed, but |
10 | 21 | are assumed OK. Remaining tasks are normally performed; |
11 | 22 | it() tt(--help (-h)): (C) Display help information and exit; |
12 | it() tt(--log (-L) <path>): log messages are appended to `path'. If path | |
13 | does not exist, it is first created; | |
23 | it() tt(--log (-L) <file-spec>): log messages are appended to | |
24 | `file-spec'. If file-spec does not exist, it is first created; | |
14 | 25 | it() tt(--logmail): mail sent by s() is logged (requires tt(--log) or |
15 | 26 | tt(--syslog)); |
16 | 27 | it() tt(--max-size <size>[BKMG]): files retrieved by tt(GET) commands may |
28 | 39 | interval of <interval> seconds (or minutes if an `m' is appended (no |
29 | 40 | blanks) to <interval>) following the delay specified at tt(--repeat) |
30 | 41 | (see below). This option requires specification of the tt(--repeat) |
31 | option; | |
32 | it() tt(--reload <pid-file>): (C) reloads the configuration and skip-files | |
33 | and restarts the scan of the s() daemon process. | |
42 | and tt(--daemon) options; | |
43 | it() tt(--reload <uds>): (C) reloads the configuration and skip-files | |
44 | and restarts the scan of the s() daemon process. Options defined in | |
45 | the policy file are also reloaded. However, command-line options | |
46 | always take priority over options defined in the policy file, so when | |
47 | command-line options were used when starting s() in daemon mode, they | |
48 | cannot be modified by reloading the policy file. | |
34 | 49 | it() tt(--repeat <seconds>): wake up and perform an integrity scan at |
35 | 50 | interrupts or after tt(<seconds>) seconds (or minutes if an `m' is |
36 | 51 | appended (no blanks) to <seconds>) after completing the previous |
37 | 52 | integrity scan. The option tt(--random-interval) can be used to add a |
38 | 53 | random delay to tt(<seconds>) until the next integrity scan is |
39 | performed. | |
40 | it() tt(--rerun <pid-file>): start executing the integrity scan commands | |
41 | that are specifed in the s() daemon process's policy file; | |
42 | it() tt(--resume <pid-file>): (C) resume a suspended s() process, implies | |
54 | performed. This option requires specification of the and tt(--daemon) | |
55 | option; | |
56 | it() tt(--rerun <uds>): (C) start executing the integrity scan | |
57 | commands that are specifed in the s() daemon process's policy file; | |
58 | it() tt(--resume <uds>): (C) resume a suspended s() process, implies | |
43 | 59 | tt(--rerun); |
44 | 60 | it() tt(--run-command (-r) <nr>): (C) Only execute command number <nr> |
45 | 61 | (natural number). Command numbers are shown by s() |
46 | tt(---parse-policy-file); | |
47 | it() tt(--skip-files (-s) <skippath>): all entries in tt(skippath) | |
48 | (specified using an em(absolute path)) are skipped. Their integrity is | |
49 | not monitored. If an entry is already present in a log file then s() | |
50 | once generates an tt(IGNORING) message in the mail sent to the address | |
51 | specified at tt(EMAIL) in the policy file. Each entry mentioned in | |
52 | tt(filepath) must be on a line of its own and must be specified using | |
53 | absolute paths. Entries ending in a slash are assumed to be | |
54 | directories whose full contents must be skipped. Other entries are | |
55 | interpreted as the path names of files to skip. Initial and trailing | |
56 | blanks, empty lines and lines having a tt(#) as their 1st non blank | |
57 | character are ignored. | |
62 | tt(---parse-policy-file). This option can only be specified using the | |
63 | second synopsis; | |
64 | it() tt(--skip-files (-s) <file-spec>): all entries in tt(<file-spec>) are | |
65 | skipped. Their integrity is not monitored. If an entry is already | |
66 | present in a log file then s() once generates an tt(IGNORING) message | |
67 | in the mail sent to the address specified at tt(EMAIL) in the policy | |
68 | file. Each entry mentioned in tt(file-spec) must be on a line of | |
69 | its own and must be specified using absolute file paths. Entries | |
70 | ending in a slash are assumed to be directories whose full contents | |
71 | must be skipped. Other entries are interpreted as the names | |
72 | of files to skip. Initial and trailing blanks, empty lines and lines | |
73 | having a tt(#) as their 1st non blank character are ignored. Here are | |
74 | some examples: | |
75 | verb( | |
76 | # skip all files in user's Mail directory | |
77 | /home/user/Mail/ | |
78 | # skip user's .history file | |
79 | /home/user/.history | |
80 | ) | |
58 | 81 | it() tt(--stdout (-o)): messages are (also) written to the std. output |
59 | stream (not available when for option tt(--daemon)); | |
60 | it() tt(--suspend <pid-file>): (C) suspends a currently active s() | |
61 | process. Use tt(--resume) to re-activate an s() daemon or | |
62 | tt(--terminate) to end an s() daemon; | |
82 | stream (only available with the second synopsis); | |
83 | it() tt(--suspend <uds>): (C) suspends a currently active s() | |
84 | process. Following tt(--suspend) use tt(--resume) to re-activate an | |
85 | s() daemon or tt(--terminate) to end an s() daemon; | |
63 | 86 | it() tt(--syslog): write syslog messages; |
64 | 87 | it() tt(--syslog-facility <facility>): syslog facility to use. By |
65 | 88 | default facility DAEMON is used; |
68 | 91 | it() tt(--syslog-tag <tag>): tt(<tag>) specifies the identifier that is |
69 | 92 | prefixed to syslog messages. By default the tag `STEALTH' is used, see |
70 | 93 | also the next section; |
71 | it() tt(--terminate <pid-file>): (C) terminate a currently active s() | |
94 | it() tt(--terminate <uds>): (C) terminate a currently active s() | |
72 | 95 | process; |
73 | 96 | it() tt(--time-stamp (-t) <type>): the time-stamps to use. By default |
74 | 97 | UTC. To use the local time specify tt(--time-stamp |
79 | 102 | information. Requires options tt(--log) or tt(--syslog). Possible |
80 | 103 | values are:nl() |
81 | 104 | 0: nothing is logged+nl() |
82 | 1: mode reports and policy commands+nl() | |
105 | 1: (default) mode reports and policy commands+nl() | |
83 | 106 | 2: also: ipc commands and actions+nl() |
84 | 107 | 3: also: integrity scan informative messages |
85 | 108 | it() tt(--version (-v)): (C) Display s()'s version information and |
87 | 110 | ) |
88 | 111 | |
89 | 112 | itemization( |
90 | it() tt(<pid-file>): absolute filename of a file that is used for | |
91 | communication with a s() daemon process; | |
92 | it() tt(policy): path to the policy file; | |
113 | it() tt(policy): file specification of the policy file. If a relative | |
114 | location is specified then this location is interpreted relative to | |
115 | the current working directory. S() converts this relative | |
116 | specification to an absolute file location, and an option like | |
117 | tt(--reload) will reload the policy file from the thus determined | |
118 | absolute file path. | |
93 | 119 | ) |
94 | 120 | |
95 | Only one of the options tt(--daemon, --reload, --rerun, --resume, | |
96 | --suspend,) and tt(--terminate) can be specified. The options tt(--reload, | |
121 | Only one of the options tt(--daemon, --reload, --resume, | |
122 | --suspend) or tt(--terminate) can be specified. The options tt(--reload, | |
97 | 123 | --rerun, --resume, --suspend,) and tt(--terminate) ignore any other options. |
98 | 124 | |
99 | 125 | The following options are still recognized for backward compatibility with s() |
100 | pre-3.00 versions and will be removed in future versions. They generate error | |
101 | messages suggesting alternatives: | |
126 | pre-3.00 versions and will be removed in a future s() version. They generate | |
127 | error messages suggesting alternatives: | |
102 | 128 | |
103 | 129 | itemization( |
104 | 130 | it() tt(--echo-commands (-e)): |
109 | 135 | tt(--stdout) instead. |
110 | 136 | it() tt(--quiet (-q)): suppresses progress messages written to stderr; use |
111 | 137 | tt(--verbosity 0) instead. |
112 | it() tt(--suppress <pid-file>): suppresses a currently active s() | |
138 | it() tt(--suppress <uds>): suppresses a currently active s() | |
113 | 139 | process; use tt(--suspend) instead. |
114 | 140 | ) |
115 | 141 | |
116 | The following options were discontinued starting with s() version 3.00.00: | |
142 | The following options were discontinued starting since s() version 3.00.00: | |
117 | 143 | itemization( |
118 | 144 | it() tt(--debug) (option tt(--verbosity) or tt(--dry-run) could be used |
119 | 145 | instead); |
121 | 147 | it() tt(--parse-config-file). |
122 | 148 | ) |
123 | 149 | |
124 | When specifying long options in policy files the initial hyphens should be | |
150 | When specifying long options in policy files initial hyphens should be | |
125 | 151 | omitted. Here are some examples: |
126 | 152 | verb( %% |
127 | 153 | log /tmp/stealth.log |
8 | 8 | |
9 | 9 | For example, if a s() process was once started using the command |
10 | 10 | COMMENT(KEEP A BLANK FOLLOWING THE BACKSLASH) |
11 | verb( stealth --daemon /var/run/small.pid --repeat 900 \ | |
12 | /var/stealth/policies/small.pol) | |
11 | verb( | |
12 | stealth --daemon /root/stealth/small.uds --repeat 900 \ | |
13 | /root/stealth/small.pol) | |
13 | 14 | then the tt(--suspend) and tt(--resume) commands for this process should |
14 | 15 | be called as: |
15 | verb( stealth --suspend /var/run/small.pid | |
16 | stealth --resume /var/run/small.pid) | |
16 | verb( stealth --suspend /root/stealth/small.uds | |
17 | stealth --resume /root/stealth/small.uds) | |
17 | 18 | The s() process identified in the files provided as arguments to |
18 | 19 | the tt(--suspend) and tt(--resume) options is called the em(daemon stealth |
19 | 20 | process) below. |
26 | 27 | except for tt(--resume) (see below) and tt(--terminate). |
27 | 28 | it() Any scheduled integrity scans following the tt(--suspend) command |
28 | 29 | are ignored by the daemon s() process; |
29 | it() The daemon s() process writes a message that it is | |
30 | being suspended to the report file and then processes the report file as | |
31 | usual. | |
30 | it() The daemon s() process writes a message that it is being suspended to | |
31 | the report file and then processes the report file as usual. | |
32 | 32 | ) |
33 | Now that the report file will no longer be affected by the daemon | |
33 | Now that the report file is no longer modified by the daemon | |
34 | 34 | s() process, log-rotation may take place. E.g., a program like |
35 | 35 | bf(logrotate)(1) allows its users to specify a command or script just before |
36 | log-rotation takes place, and `s() tt(--suspend pidfile)' could be | |
36 | log-rotation takes place, and `s() tt(--suspend udsfile)' could be | |
37 | 37 | specified nicely in such a pre-rotation section. |
38 | 38 | |
39 | 39 | The tt(--resume) option has the following effect: |
53 | 53 | itemization( |
54 | 54 | it() Wait for the daemon s() process to complete an ongoing series of |
55 | 55 | integrity scan commands; |
56 | it() Issue the `s() tt(--terminate pidfile)' command. | |
56 | it() Issue the `s() tt(--terminate udsfile)' command. | |
57 | 57 | ) |
3 | 3 | the absolute paths of entries to be skipped. Each entry should appear on a |
4 | 4 | line of its own without any additional information. |
5 | 5 | |
6 | S() can be informed about this file using the tt(--skip-files skippath) | |
7 | option. The file holding the paths of the entries to be skipped should be | |
8 | specified using absolute paths, using one entry per line. Initial and trailing | |
9 | blanks, empty lines and lines having a tt(#) as their first non blank | |
10 | character are ignored. | |
6 | S() can be informed about this file using the tt(--skip-files <file-spec>) | |
7 | option. When a relative file specification is used with tt(--skip-files) it is | |
8 | interpreted a location relative to the current working directory. The | |
9 | skip-files file itself must contain the paths of the entries to be skipped | |
10 | during file integrity scans. If an entry is already present in a log file then | |
11 | s() once generates an tt(IGNORING) message in the mail sent to the address | |
12 | specified at tt(EMAIL) in the policy file. Each entry in a skip-file must be | |
13 | on a line of its own and must be specified using absolute file paths. Entries | |
14 | ending in a slash are assumed to be directories whose full contents must be | |
15 | skipped. Other entries are interpreted as the names of files to skip. Initial | |
16 | and trailing blanks, empty lines and lines having a tt(#) as their 1st non | |
17 | blank character are ignored. | |
11 | 18 | |
12 | 19 | Here is an example: |
13 | verb( stealth -e --skip-files /root/stealth/remote/skipping remote.pol) | |
20 | verb( | |
21 | stealth -e --skip-files /root/stealth/remote/skipping remote.pol) | |
14 | 22 | |
15 | 23 | If an entry tt(/etc/skipme) appears in the current logs which is thereafter |
16 | 24 | added to the tt(skippath) file then the mail generated by s() |
27 | 27 | tt(/etc/stealth/cleanup.rc) and the tt(stealthcleanup) script itself in |
28 | 28 | tt(/usr/bin/stealthcleanup), the tt(stealthcleanup) script could be called |
29 | 29 | as follows: |
30 | verb( /usr/bin/stealthcleanup /etc/stealth/cleanup.rc) | |
30 | verb( | |
31 | /usr/bin/stealthcleanup /etc/stealth/cleanup.rc) | |
31 | 32 | Note that tt(stealthcleanup) may be called whether or not there are active |
32 | s() processes, as s() does not use status files anymore once | |
33 | they have been written. | |
33 | s() processes. | |
34 | ||
35 | ||
36 | ||
37 |
0 | Next we specify some tt(USE) directives, to fit our specific, local, | |
1 | situation: | |
2 | verb( USE BASE /root/stealth/client | |
0 | Next some tt(USE) directives, matching our specific, local, | |
1 | situation, are defined: | |
2 | verb( | |
3 | USE BASE /root/stealth/client | |
3 | 4 | USE EMAIL admin@elswhere |
4 | 5 | USE MAILER /root/bin/stealthmail |
5 | 6 | USE MAILARGS "Client STEALTH report" |
6 | 7 | USE SSH ${SSHCMD}) |
8 | ||
7 | 9 | itemization( |
8 | 10 | it() All output is written under the tt(/root/stealth/client) directory; |
9 | 11 | it() Mail is sent to the user tt(admin@elsewhere); |
52 | 52 | chapter(Granting access) |
53 | 53 | includefile(access/intro) |
54 | 54 | |
55 | subsect(The controller's user: creating an ssh-key) | |
56 | includefile(access/controller) | |
55 | subsect(The monitor's user: creating an ssh-key) | |
56 | includefile(access/monitor) | |
57 | 57 | |
58 | subsect(The client's account: accepting ssh from the controller's user) | |
58 | subsect(The client's account: accepting ssh from the monitor's user) | |
59 | 59 | includefile(access/client) |
60 | 60 | |
61 | 61 | subsect(Logging into the account@client account) |
124 | 124 | subsubsect(Checking the client's setuid/setgid files) |
125 | 125 | includefile(running/checkingsetuid) |
126 | 126 | |
127 | subsubsect(Checking the configuration files in the client's /etc/ directory) | |
127 | subsubsect(Checking the configuration files in the | |
128 | client's /etc/ directory) | |
128 | 129 | includefile(running/checkingconfig) |
129 | 130 | |
130 | 131 | subsect(The complete `policy' file) |
0 | With 4.00.00: | |
1 | ||
2 | itemization( | |
3 | it() Version 3.00.00 was only short-lived. The inter-process communication | |
4 | using signals never ran smoothly. Version 4.00.00 re-implements s()'s | |
5 | inter-process communication using Unix Domain Sockets. | |
6 | it() Previously required absolute file paths are no longer required. When | |
7 | relative file paths are used with the s() daemon or with s() | |
8 | performing an integrity scan as foreground process they are | |
9 | interpreted relatively to the current working directory. Relative | |
10 | file locations for options specified in the second section of the | |
11 | policy file are interpreted relative to the location of the policy | |
12 | file, and relative path specifications used in the first section of | |
13 | the policy file are interpreted relative to the policy file's tt(USE | |
14 | BASE). | |
15 | it() The README.flow file is provided with several separately provided | |
16 | illustrative images in the distribution-provided directory | |
17 | tt(documentation/images). | |
18 | it() Specifications for the logrotate specifications should use | |
19 | 'tt(copytruncate)' and 'tt(sharedscripts)' (see section ref(ROTATE) | |
20 | for an example) | |
21 | it() Examples in the manual still use tt(sha1sum) when checking hash | |
22 | values. Stronger hash functions (like tt(sha256sum)) might be | |
23 | preferred in practice. When updating existing policy files to use | |
24 | tt(sha256sum) rather than tt(sha1sum) realize that tt(sha256sum's) | |
25 | hash values are longer than tt(sha1sum's) hash values, and that | |
26 | therefore log files obtained when tt(sha1sum) was used are | |
27 | incompatible with log files obtained when tt(sha256sum) was used. In | |
28 | practice this means that new log files need to be generated, | |
29 | disregarding any previously geneerated log files. | |
30 | ) | |
31 | ||
32 | ||
0 | 33 | COMMENT( |
1 | 34 | With 3.00.00: |
2 | ) | |
35 | ||
3 | 36 | itemization( |
4 | 37 | it() Internally the flow control handling, in particular with s() running |
5 | 38 | as a daemon, has completely been redesigned. |
46 | 79 | (some) long option specifications. See section ref(OPTIONS) for |
47 | 80 | details. |
48 | 81 | ) |
82 | ) | |
49 | 83 | |
50 | 84 | COMMENT( |
51 | 85 | With 2.02.00: |
117 | 151 | |
118 | 152 | Two new options were added to facilitate report-file rotations: |
119 | 153 | itemization( |
120 | it() tt(--resume pidfile): resume a suppressed s() | |
154 | it() tt(--resume pidfile): resume a suspended s() | |
121 | 155 | process (implying tt(--rerun)); |
122 | it() tt(--suppress pidfile): suppress a currently active s() | |
123 | process. All scheduled scans following tt(--suppress) are skipped, | |
156 | it() tt(--suspend pidfile): suspend a currently active s() | |
157 | process. All scheduled scans following tt(--suspend) are skipped, | |
124 | 158 | tt(--rerun) is ignored, but tt(--resume) and tt(--terminate) |
125 | 159 | can be issued; |
126 | 160 | ) |
127 | 161 | The report file should not be modified while integrity scans take |
128 | 162 | place. The new options were added to make sure this requirement is met when |
129 | 163 | the report file must be rotated. The bf(ssh) connections to clients remain |
130 | open between pairs of tt(--suppress) and tt(--resume) commands. See section | |
164 | open between pairs of tt(--suspend) and tt(--resume) commands. See section | |
131 | 165 | ref(ROTATE) for details about these two options. |
132 | 166 | |
133 | Issues related to suppressing s() runs are: | |
167 | Issues related to suspending s() runs are: | |
134 | 168 | itemization( |
135 | 169 | it() cleaning up obsolete status files (section ref(STATUS)); |
136 | 170 | it() automating report- and status file rotation using external |
0 | 0 | #include "INSTALL.im" |
1 | 1 | |
2 | 2 | #undef CXXFLAGS |
3 | #define CXXFLAGS "--std=c++11 -Wall -O2 -pthread" | |
3 | #define CXXFLAGS "--std=c++14 -Wall -O2 -pthread" | |
4 | 4 | |
5 | 5 | #define MAIN "main.cc" |
6 | 6 | #define ADD_LIBRARIES "bobcat" |
10 | 10 | #define REFRESH |
11 | 11 | #define LIBRARY "modules" |
12 | 12 | #define SHAREDREQ "" |
13 | #define CLS | |
14 | 13 | #define USE_ALL "a" |
15 | 14 | #define SOURCES "*.cc" |
16 | 15 | #define SCANGEN "" |
0 | // This icmconf file is used for compiling class-specific libraries in | |
1 | // sub-directories. | |
2 | ||
0 | 3 | #define USE_ECHO ON |
1 | 4 | #define CLS |
2 | 5 | |
4 | 7 | #define THREAD "" |
5 | 8 | #endif |
6 | 9 | |
7 | #define CXX "g++" | |
8 | #define CXXFLAGS "--std=c++11 " ${THREAD} " -Wall -O2" | |
10 | //#define CXX "g++" | |
11 | #define CXX "g++-5" | |
12 | ||
13 | #define CXXFLAGS "--std=c++14 " ${THREAD} " -Wall -O2" | |
9 | 14 | #define SOURCES "*.cc" |
10 | 15 | #define TMP_DIR "tmp" |
11 | 16 | #define OBJ_EXT ".o" |
2 | 2 | void IntegrityScanner::checkSize(std::string const &fname, off_t length) |
3 | 3 | { |
4 | 4 | if (length > d_maxSize) |
5 | d_stealthLog << | |
5 | fmsg << | |
6 | 6 | "STEALTH - CAN'T CONTINUE: `" << fname << "' EXCEEDS MAX. " |
7 | 7 | "DOWNLOAD SIZE (" << d_options.maxSizeStr() << ")\n" |
8 | 8 | "STEALTH - THIS COULD POINT TO A SERIOUS SITUATION EXISTING AT " |
9 | 9 | "THE CLIENT\n" |
10 | 10 | "STEALTH - THIS CONDITION MAY HAVE INVALIDATED THE CLIENT'S LOG " |
11 | 11 | "FILES\n" |
12 | "STEALTH - *** INVESTIGATE ***" << StealthEnums::leave; | |
12 | "STEALTH - *** INVESTIGATE ***" << noidl; | |
13 | 13 | } |
14 | 14 | |
15 | 15 |
6 | 6 | ofstream currentReport(fname.c_str()); |
7 | 7 | |
8 | 8 | if (!currentReport) |
9 | d_stealthLog << "Can't open `" << fname << "' to write" << | |
10 | StealthEnums::leave; | |
9 | fmsg << "Can't open `" << fname << "' to write" << noidl; | |
11 | 10 | |
12 | 11 | m3 << "copy: about to read child input" << endl; |
13 | 12 |
3 | 3 | void IntegrityScanner::execute(string const &cmd) |
4 | 4 | { |
5 | 5 | if (!(s_firstWord << cmd)) // determine first word and the rest |
6 | d_stealthLog << "Corrupt line in policy file: " << cmd << | |
7 | StealthEnums::leave; | |
6 | fmsg << "Corrupt line in policy file: " << cmd << noidl; | |
8 | 7 | else |
9 | 8 | m1 << cmd << endl; |
10 | 9 |
16 | 16 | string source = s_firstWord[1]; // get the (remote) source |
17 | 17 | |
18 | 18 | if (!source.length()) |
19 | d_stealthLog << "GET command requires source and destination" << | |
20 | StealthEnums::leave; | |
19 | fmsg << "GET command requires source and destination" << noidl; | |
21 | 20 | |
22 | 21 | s_firstWord.match(s_firstWord[3]); // strip off source |
23 | 22 | string destination = s_firstWord[1]; // get the local dest. |
24 | 23 | |
25 | 24 | if (!destination.length()) |
26 | d_stealthLog << | |
27 | "GET " << source << " <destination>': destination missing" << | |
28 | StealthEnums::leave; | |
25 | fmsg << "GET " << source << | |
26 | " <destination>': destination missing" << noidl; | |
29 | 27 | |
30 | 28 | if (Stat(destination).isType(Stat::DIRECTORY)) // is the dest. a dir. ? |
31 | 29 | destination += "/" + fileName(source); |
9 | 9 | #include <bobcat/process> |
10 | 10 | #include <bobcat/pattern> |
11 | 11 | |
12 | #include "../stealthenums/stealthenums.h" | |
13 | ||
12 | 14 | class PolicyFile; |
13 | 15 | class RunMode; |
14 | 16 | class Options; |
15 | 17 | |
16 | class IntegrityScanner | |
18 | class IntegrityScanner: public StealthEnums | |
17 | 19 | { |
18 | 20 | typedef std::vector<std::string> StringVector; |
19 | 21 | typedef StringVector::const_iterator const_iterator; |
20 | 22 | |
21 | 23 | Options &d_options; |
22 | RunMode &d_run; | |
24 | RunMode const &d_pending; | |
23 | 25 | PolicyFile &d_policyFile; |
24 | std::ostream &d_stealthLog; | |
26 | std::ostream &d_report; | |
27 | ||
25 | 28 | FBB::Pattern d_firstWord; |
26 | 29 | FBB::Process d_sshFork; |
27 | 30 | FBB::Process d_shFork; |
29 | 32 | std::string d_label; |
30 | 33 | const_iterator d_cmdIterator; |
31 | 34 | bool d_testExitValue; |
35 | bool d_active = false; | |
32 | 36 | size_t d_nScans; |
33 | 37 | off_t d_maxSize; |
34 | 38 | StringVector d_skipFiles; |
35 | std::string d_skipFilePath; | |
39 | std::string d_skipFile; | |
36 | 40 | size_t d_diffPrefix; |
37 | 41 | size_t d_pathOffset; // begin of the abs path if not |
38 | 42 | // at the first / on a line |
47 | 51 | static FBB::Pattern s_exitValue; |
48 | 52 | |
49 | 53 | public: |
50 | IntegrityScanner(RunMode &run, PolicyFile &sorter, | |
51 | std::ostream &stealthlog); | |
54 | IntegrityScanner(RunMode const &pending, Options &options, | |
55 | PolicyFile &policyFile, std::ostream &stealthlog); | |
52 | 56 | |
53 | 57 | size_t nScans() const |
54 | 58 | { |
58 | 62 | void loadSkipFiles(); |
59 | 63 | void nScansReset(); |
60 | 64 | // run one series of tests |
61 | void run(); | |
65 | void run(); | |
62 | 66 | |
63 | 67 | void killChildren(); |
64 | ||
68 | ||
69 | bool active() const; | |
70 | ||
65 | 71 | private: |
66 | 72 | |
67 | 73 | void foreground(size_t cmdNr); // run 1 command |
175 | 181 | d_nScans = 0; |
176 | 182 | } |
177 | 183 | |
184 | inline bool IntegrityScanner::active() const | |
185 | { | |
186 | return d_active; | |
187 | } | |
188 | ||
178 | 189 | #endif |
0 | 0 | #include "integrityscanner.h" |
1 | ||
2 | #include <sstream> | |
1 | 3 | |
2 | 4 | #include <bobcat/mstream> |
3 | 5 | #include <bobcat/stat> |
4 | 6 | #include <bobcat/datetime> |
5 | 7 | #include <bobcat/stringline> |
6 | #include <bobcat/exception> | |
7 | 8 | #include <bobcat/ranger> |
8 | 9 | |
9 | 10 | #include "../util/util.h" |
10 | 11 | #include "../policyfile/policyfile.h" |
11 | #include "../stealthlog/stealthlog.h" | |
12 | 12 | #include "../runmode/runmode.h" |
13 | 13 | #include "../options/options.h" |
14 | 14 | #include "../msg/msg.h" |
0 | 0 | #include "integrityscanner.ih" |
1 | 1 | |
2 | 2 | /* |
3 | Since the IntegrityScanner's destruction is also the termination of the program, no | |
4 | explicit destruction of the newly created objects is necessary. A pointer is | |
5 | used to prevent the construction of a constant object. As the constructor | |
6 | itself would create a constant object, the construction *new... | |
3 | Since the IntegrityScanner's destruction is also the termination of the | |
4 | program, no explicit destruction of the newly created objects is necessary. A | |
5 | pointer is used to prevent the construction of a constant object. As the | |
6 | constructor itself would create a constant object, the construction *new... | |
7 | 7 | is used. |
8 | 8 | |
9 | 9 | */ |
10 | 10 | |
11 | IntegrityScanner::IntegrityScanner(RunMode &run, PolicyFile &policyFile, | |
12 | ostream &stealthLog) | |
11 | IntegrityScanner::IntegrityScanner(RunMode const &pending, Options &options, | |
12 | PolicyFile &policyFile, ostream &report) | |
13 | 13 | : |
14 | d_options(Options::instance()), | |
15 | d_run(run), | |
14 | d_options(options), | |
15 | d_pending(pending), | |
16 | 16 | d_policyFile(policyFile), |
17 | d_stealthLog(stealthLog), | |
17 | d_report(report), | |
18 | 18 | d_firstWord("(\\S+)(\\s+(.*))?"), // firstword ([1]) and the |
19 | 19 | // rest ([3]) of a text |
20 | 20 | d_sshFork |
37 | 37 | d_pathOffset(numeric_limits<size_t>::max()) |
38 | 38 | { |
39 | 39 | setSentinel(); |
40 | ||
41 | 40 | loadSkipFiles(); |
42 | ||
43 | m2 << "(re)constructed the Integrity Scanner" << endl; | |
44 | m3 << "max. download size: " << d_options.maxSizeStr() << endl; | |
45 | 41 | } |
46 | ||
47 | ||
48 | ||
49 | ||
50 | ||
51 | ||
52 | ||
53 |
1 | 1 | |
2 | 2 | void IntegrityScanner::loadSkipFiles() |
3 | 3 | { |
4 | d_skipFilePath = d_options.skipFilePath(); | |
4 | d_skipFile = d_options.skipFile(); | |
5 | 5 | |
6 | if (d_skipFilePath.length()) // skip files | |
6 | if (d_skipFile.length()) // skip files | |
7 | 7 | setSkip(); |
8 | 8 | else // or don't skip |
9 | 9 | d_skip = &IntegrityScanner::dontSkip; |
21 | 21 | if (removeFirstWord("CHECK")) // ... CHECK ... |
22 | 22 | { |
23 | 23 | if (!doCHECKcommand(d_shFork)) // so, do the command |
24 | d_stealthLog << "\n" // and check the result | |
24 | d_report << "\n" // and check the result | |
25 | 25 | "*** BE CAREFUL *** REMAINING RESULTS MAY BE FORGED\n" << |
26 | 26 | endl; |
27 | 27 | } |
10 | 10 | "/bin/echo \"" << d_sentinel << " $?\"" << endl; |
11 | 11 | |
12 | 12 | if (!out) |
13 | d_stealthLog << "Inserting command `" << s_firstWord[0] << | |
14 | "' failed." << StealthEnums::leave; | |
13 | fmsg << "Inserting command `" << s_firstWord[0] << "' failed." << | |
14 | noidl; | |
15 | 15 | } |
45 | 45 | // of the pair. |
46 | 46 | // |
47 | 47 | // At the end, if the hashtable has any elements, the table is inserted |
48 | // into the d_stealthLog and `false' is returned. If the hashtable contains | |
48 | // into the d_report and `false' is returned. If the hashtable contains | |
49 | 49 | // no elements, 'true' is returned. |
50 | 50 | |
51 | 51 | string line; |
100 | 100 | } |
101 | 101 | |
102 | 102 | if (d_label.length()) |
103 | d_stealthLog << d_label << endl; | |
103 | d_report << d_label << endl; | |
104 | 104 | |
105 | 105 | for |
106 | 106 | ( |
110 | 110 | begin++ |
111 | 111 | ) |
112 | 112 | { |
113 | d_stealthLog << begin->second.first << ": " << begin->first << endl; | |
113 | d_report << begin->second.first << ": " << begin->first << endl; | |
114 | 114 | |
115 | 115 | for |
116 | 116 | ( |
120 | 120 | sbegin != send; |
121 | 121 | sbegin++ |
122 | 122 | ) |
123 | d_stealthLog << " " << *sbegin << endl; | |
123 | d_report << " " << *sbegin << endl; | |
124 | 124 | } |
125 | 125 | |
126 | 126 | string logFilename = logfile + "." + datetime(); |
16 | 16 | |
17 | 17 | string source = s_firstWord[1]; // get the (remote) source |
18 | 18 | if (!source.length()) |
19 | d_stealthLog << "PUT command requires source and destination" << | |
20 | StealthEnums::leave; | |
19 | fmsg << "PUT command requires source and destination" << noidl; | |
21 | 20 | |
22 | 21 | s_firstWord.match(s_firstWord[3]); // strip off source |
23 | 22 | |
24 | 23 | string destination = s_firstWord[1]; // get the local dest. |
25 | 24 | if (!destination.length()) |
26 | d_stealthLog << "At `PUT " << source << | |
25 | fmsg << "At `PUT " << source << | |
27 | 26 | " <destination>': destination missing" << |
28 | StealthEnums::leave; | |
27 | noidl; | |
29 | 28 | |
30 | 29 | if (Stat(destination).isType(Stat::DIRECTORY)) // is the dest. a dir. ? |
31 | 30 | destination += "/" + fileName(source); // then append sourcename |
5 | 5 | struct stat statbuf; |
6 | 6 | |
7 | 7 | if (stat(source.c_str(), &statbuf)) |
8 | d_stealthLog << "PUT " << source << ": can't stat it" << StealthEnums::leave; | |
8 | fmsg << "PUT " << source << ": can't stat it" << noidl; | |
9 | 9 | |
10 | 10 | ostringstream command; |
11 | 11 |
6 | 6 | ofstream target(fname.c_str()); |
7 | 7 | |
8 | 8 | if (!target) |
9 | d_stealthLog << "Can't open `" << fname << "' to write" << | |
10 | StealthEnums::leave; | |
9 | fmsg << "can't write `" << fname << '\'' << noidl; | |
11 | 10 | |
12 | 11 | char c; |
13 | 12 | string partialSentinel; |
17 | 16 | |
18 | 17 | while (true) |
19 | 18 | { |
20 | if (!src.read(&c, 1)) // read char by char | |
21 | { | |
22 | d_run.setMode(RunMode::TERMINATE); | |
23 | d_stealthLog << "Incomplete read from `" << fname << "'" << | |
24 | StealthEnums::leave; | |
25 | return; | |
26 | } | |
19 | if (not src.read(&c, 1)) // read char by char | |
20 | fmsg << "Incomplete read from `" << fname << "'" << noidl; | |
27 | 21 | |
28 | 22 | checkSize(fname, ++size); // throws if not OK |
29 | 23 |
1 | 1 | |
2 | 2 | void IntegrityScanner::run() |
3 | 3 | { |
4 | d_active = true; | |
5 | ||
4 | 6 | ++d_nScans; |
5 | 7 | |
6 | 8 | setSentinel(); // determine d_sentinel |
18 | 20 | |
19 | 21 | for (auto &cmd: ranger(d_cmdIterator, beyond)) |
20 | 22 | { |
21 | if (d_run.interrupted()) // terminate, suspend, reload | |
23 | if (d_pending.hasMode(SUSPEND | RELOAD | TERMINATE)) | |
22 | 24 | { |
23 | 25 | m1 << "integrity scan interrupted by " << |
24 | d_run.modeName() << " request" << endl; | |
25 | return; | |
26 | d_pending << " request" << endl; | |
27 | d_active = false; | |
26 | 28 | } |
27 | ||
28 | 29 | execute(cmd); |
29 | 30 | } |
30 | 31 | } |
31 | 32 | |
32 | 33 | m3 << "policy file processed" << endl; |
34 | d_active = false; | |
33 | 35 | } |
34 | ||
35 | ||
36 | ||
37 | ||
38 |
4 | 4 | string current = logfile + ".cur"; // create current logfile |
5 | 5 | |
6 | 6 | if (!Util::mkdir(current)) // make sure directory exists |
7 | d_stealthLog << "Unable to create the logfile `" << current << "'" << | |
8 | StealthEnums::leave; | |
7 | fmsg << "unable to create the logfile `" << current << '\'' << noidl; | |
9 | 8 | |
10 | 9 | m3 << "logs to " << current << endl; |
11 | 10 | |
12 | 11 | copy(extractor, current); // copy the info in extractor |
13 | 12 | // to the current logfile |
14 | 13 | |
15 | if (access(logfile.c_str(), R_OK)) // no old report yet | |
14 | if (access(logfile.c_str(), R_OK) != 0) // no old report yet | |
16 | 15 | { |
17 | 16 | m3 << "writing new report: " << logfile << '\n'; |
18 | 17 | |
19 | 18 | rename(current.c_str(), logfile.c_str()); // install `logfile' |
20 | 19 | |
21 | 20 | if (d_label.length()) |
22 | d_stealthLog << d_label << endl; | |
21 | d_report << d_label << endl; | |
23 | 22 | |
24 | d_stealthLog << "Initialized report on " << logfile << endl; | |
23 | d_report << "Initialized report on " << logfile << endl; | |
25 | 24 | |
26 | 25 | m3 << "initialized report on " << logfile << endl; |
27 | 26 | return true; |
1 | 1 | |
2 | 2 | void IntegrityScanner::setSkip() |
3 | 3 | { |
4 | ifstream in; | |
5 | Exception::open(in, d_skipFilePath); | |
4 | ifstream in(d_skipFile); | |
5 | if (not in) | |
6 | fmsg << "cannot read skip-file `" << d_skipFile << '\'' << noidl; | |
6 | 7 | |
7 | 8 | for_each( |
8 | 9 | istream_iterator<StringLine>(in), istream_iterator<StringLine>(), |
19 | 20 | |
20 | 21 | |
21 | 22 | |
23 |
3 | 3 | std::string const &exitStr) |
4 | 4 | { |
5 | 5 | if (not (s_exitValue << exitStr)) |
6 | d_stealthLog << "No exit value for\n" << | |
6 | fmsg << "No exit value for\n" << | |
7 | 7 | cmd << "\n" |
8 | "NOTE: this is the literal text of the executed command. " | |
9 | "Maybe a typo?" << RunMode::leave; | |
8 | "ADVICE: this is the literal text of the executed command. " | |
9 | "Maybe a typo?" << noidl; | |
10 | 10 | |
11 | 11 | if (d_testExitValue && stoul(s_exitValue[1]) != 0) |
12 | d_stealthLog << | |
13 | d_options.basename() << | |
12 | fmsg << d_options.basename() << | |
14 | 13 | " terminated: non-zero exit value for\n" << |
15 | *d_cmdIterator << " (" << exitStr << ")" << RunMode::leave; | |
14 | *d_cmdIterator << " (" << exitStr << ")" << noidl; | |
16 | 15 | } |
17 | 16 | |
18 | 17 |
6 | 6 | ifstream source(fname.c_str()); |
7 | 7 | |
8 | 8 | if (!source) |
9 | d_stealthLog << "Can't open `" << fname << "' to read." << | |
10 | StealthEnums::leave; | |
9 | fmsg << "can't read `" << fname << '\'' << noidl; | |
11 | 10 | |
12 | 11 | m3 << "about to read local `" << fname << '\'' << endl; |
13 | 12 | |
22 | 21 | break; |
23 | 22 | |
24 | 23 | if (!d_sshFork.write(buffer, nRead)) |
25 | d_stealthLog << "PUT failed." << StealthEnums::leave; | |
24 | fmsg << "PUT failed." << noidl; | |
26 | 25 | } |
27 | 26 | |
28 | 27 | d_sshFork.flush(); |
0 | #include "ipc.ih" | |
1 | ||
2 | LinearMap<std::string, StealthEnums::Mode> const IPC::s_request = | |
3 | { | |
4 | {"suspend", SUSPEND}, | |
5 | {"resume", RESUME}, | |
6 | {"rerun", RERUN}, | |
7 | {"reload", RELOAD}, | |
8 | {"terminate", TERMINATE}, | |
9 | }; |
0 | #ifndef INCLUDED_IPC_ | |
1 | #define INCLUDED_IPC_ | |
2 | ||
3 | #include <string> | |
4 | ||
5 | //#include <bobcat/selector> | |
6 | ||
7 | ||
8 | #include <bobcat/linearmap> | |
9 | ||
10 | #include "../stealthenums/stealthenums.h" | |
11 | #include "../wait11/wait11.h" | |
12 | ||
13 | class Options; | |
14 | ||
15 | class IPC: public StealthEnums | |
16 | { | |
17 | Options &d_options; | |
18 | ||
19 | Wait11 d_wait11; | |
20 | ||
21 | std::string d_requestText; | |
22 | size_t d_requestorPid = 0; | |
23 | size_t d_daemonPid; | |
24 | ||
25 | static FBB::LinearMap<std::string, Mode> const s_request; | |
26 | ||
27 | public: | |
28 | IPC(); | |
29 | // always returns true, or | |
30 | bool signalDaemon(); // throws exception on failure | |
31 | ||
32 | StealthEnums::Mode request(); // retrieve the request/msg and | |
33 | // requestor's pid | |
34 | std::string const &requestText() const; | |
35 | ||
36 | void sendRequestor(std::string const &msg); | |
37 | ||
38 | void signaled(); // call after receiving a signal | |
39 | ||
40 | void wait(bool doM2 = true); // wait until signaled | |
41 | ||
42 | void timedWait(); // wait until signaled or wait | |
43 | // until --repeat time has passed | |
44 | ||
45 | void timedWait(size_t seconds); // wait until signaled or wait | |
46 | // until seconds has passed | |
47 | // (no m2 messages), called from | |
48 | // the ipc-modes | |
49 | ||
50 | bool timeout() const; // true if timedWait's waiting | |
51 | // time has expired | |
52 | ||
53 | void writeRunFile(pid_t pid); | |
54 | ||
55 | void write(std::string const &msg) const; // write msg and own pid | |
56 | // to the runfile | |
57 | size_t daemonPid() const; | |
58 | ||
59 | private: | |
60 | void readDaemonPid(); | |
61 | void sendRequest(char const *request, pid_t pid); | |
62 | }; | |
63 | ||
64 | inline void IPC::timedWait(size_t seconds) | |
65 | { | |
66 | d_wait11.waitFor(seconds, false); | |
67 | } | |
68 | ||
69 | inline void IPC::signaled() | |
70 | { | |
71 | d_wait11.notify(); | |
72 | } | |
73 | ||
74 | inline bool IPC::timeout() const | |
75 | { | |
76 | return not d_wait11.signaled(); | |
77 | } | |
78 | ||
79 | inline std::string const &IPC::requestText() const | |
80 | { | |
81 | return d_requestText; | |
82 | } | |
83 | ||
84 | inline size_t IPC::daemonPid() const | |
85 | { | |
86 | return d_daemonPid; | |
87 | } | |
88 | ||
89 | #endif | |
90 |
0 | #include "ipc.h" | |
1 | ||
2 | #include <fstream> | |
3 | #include <limits> | |
4 | #include <csignal> | |
5 | ||
6 | #include <bobcat/mstream> | |
7 | #include <bobcat/exception> | |
8 | ||
9 | // #include "../lock/lock.h" | |
10 | #include "../options/options.ih" | |
11 | #include "../msg/msg.h" | |
12 | ||
13 | using namespace std; | |
14 | using namespace FBB; | |
15 |
0 | #include "ipc.ih" | |
1 | ||
2 | // daemonPid() obtains the process-id from an existing run-file. The file must | |
3 | // exist and the pid stored in the lock-file must be the process-id of an | |
4 | // existing Stealth program. | |
5 | ||
6 | void IPC::readDaemonPid() | |
7 | { | |
8 | ifstream in; | |
9 | ||
10 | string const &runFile = d_options.runFile(); | |
11 | ||
12 | Exception::open(in, runFile); | |
13 | ||
14 | pid_t pid; | |
15 | ||
16 | if (not (in >> pid)) | |
17 | fmsg << "daemonPid: Can't read `" << runFile << '\'' << endl; | |
18 | ||
19 | d_daemonPid = pid; | |
20 | } | |
21 | ||
22 | ||
23 | ||
24 | ||
25 | ||
26 |
0 | #include "ipc.ih" | |
1 | ||
2 | StealthEnums::Mode IPC::request() | |
3 | { | |
4 | ifstream runFile; | |
5 | Exception::open(runFile, d_options.runFile()); | |
6 | ||
7 | runFile.ignore(numeric_limits<int>::max(), '\n'); | |
8 | ||
9 | getline(runFile, d_requestText) >> d_requestorPid; | |
10 | ||
11 | auto iter = s_request.find(d_requestText); | |
12 | ||
13 | return iter == s_request.end() ? Mode::UNKNOWN : iter->second; | |
14 | } |
0 | #include "ipc.ih" | |
1 | ||
2 | void IPC::sendRequest(char const *request, pid_t pid) | |
3 | { | |
4 | if (kill(pid, SIGUSR1) != 0) | |
5 | { | |
6 | unlink(d_options.runFile().c_str()); | |
7 | ||
8 | fmsg << "Can't send signal SIGUSR1 to process `" << pid << "',\n" | |
9 | "removed stale run-file `" << d_options.runFile() << '.' << | |
10 | endl; | |
11 | } | |
12 | ||
13 | m2 << "stealth command line process sent request " << request << | |
14 | " to stealth daemon " << pid << endl; | |
15 | } | |
16 |
0 | #include "ipc.ih" | |
1 | ||
2 | void IPC::sendRequestor(string const &msg) | |
3 | { | |
4 | if (d_requestorPid == 0) | |
5 | { | |
6 | m2 << "no requestor PID. Would have sent `" << msg << '\'' << endl; | |
7 | return; | |
8 | } | |
9 | ||
10 | write(msg); | |
11 | ||
12 | if (kill(d_requestorPid, SIGUSR1) == 0) | |
13 | m2 << "to pid " << d_requestorPid << ": " << msg << endl; | |
14 | else | |
15 | m2 << "could not signal requestor " << d_requestorPid << | |
16 | " (" << msg << ')' << endl; | |
17 | ||
18 | } |
0 | #include "ipc.ih" | |
1 | ||
2 | bool IPC::signalDaemon() | |
3 | { | |
4 | readDaemonPid(); // get the pid of the daemon to signal | |
5 | ||
6 | char const *request = d_options.modeRequest(); | |
7 | ||
8 | write(request); | |
9 | ||
10 | m2 << "Sending signal SIGUSR1 to process " << d_daemonPid << endl; | |
11 | ||
12 | sendRequest(request, d_daemonPid); | |
13 | ||
14 | return true; | |
15 | } | |
16 | ||
17 |
0 | //#include "ipc.ih" | |
1 | // | |
2 | //void IPC::sleep(size_t seconds) | |
3 | //{ | |
4 | // d_selector.setAlarm(seconds); | |
5 | // wait(); | |
6 | //} | |
7 | // |
0 | #include "ipc.ih" | |
1 | ||
2 | void IPC::timedWait() | |
3 | { | |
4 | if (not d_options.repeat()) | |
5 | d_wait11.waitSignal(); | |
6 | else | |
7 | { | |
8 | size_t waitSeconds = d_options.repeatInterval() + | |
9 | d_options.randomAddition(); | |
10 | ||
11 | m2 << "waiting for " << waitSeconds << " seconds or for a signal" << | |
12 | endl; | |
13 | ||
14 | d_wait11.waitFor(waitSeconds); | |
15 | } | |
16 | } |
0 | #include "ipc.ih" | |
1 | ||
2 | void IPC::wait(bool doM2) | |
3 | { | |
4 | d_wait11.waitSignal(doM2); | |
5 | ||
6 | if (doM2) | |
7 | m2 << "continuing after wait" << endl; | |
8 | } |
0 | #include "ipc.ih" | |
1 | ||
2 | void IPC::write(string const &msg) const | |
3 | { | |
4 | fstream runFile(d_options.runFile(), ios::in | ios::out); | |
5 | ||
6 | runFile.ignore(numeric_limits<int>::max(), '\n'); // skip one line | |
7 | runFile.seekp(0, ios::cur); // prepare for writing | |
8 | runFile << msg << '\n' << // write the msg | |
9 | getpid() << '\n'; // write our own pid | |
10 | runFile.close(); // done. | |
11 | } |
0 | #include "ipc.ih" | |
1 | ||
2 | // runs in the foreground | |
3 | void IPC::writeRunFile(pid_t pid) | |
4 | { | |
5 | string const &runFileName = d_options.runFile(); | |
6 | ||
7 | ofstream runFile(runFileName); | |
8 | ||
9 | m2 << "run file: " << runFileName << '\n'; | |
10 | ||
11 | if (not (runFile << pid << endl)) | |
12 | { | |
13 | kill(SIGTERM, pid); | |
14 | fmsg << "could not write " << runFileName << endl; | |
15 | } | |
16 | } |
0 | #ifndef INCLUDED_LOCK_ | |
1 | #define INCLUDED_LOCK_ | |
2 | ||
3 | #include <iosfwd> | |
4 | #include <string> | |
5 | #include <unistd.h> | |
6 | ||
7 | class Lock | |
8 | { | |
9 | static FILE *s_runFILE; // pointer used for locking | |
10 | static std::string s_runFilename; | |
11 | ||
12 | static size_t const s_maxBlockAttempts = 10; // # seconds & tries | |
13 | // recompile lockrunfile.cc when | |
14 | // modifying this value | |
15 | public: | |
16 | enum LockType | |
17 | { | |
18 | NONBLOCKING, | |
19 | BLOCKING, | |
20 | }; | |
21 | ||
22 | static void unlockRunFile(); | |
23 | static bool lockRunFile(LockType type); | |
24 | static void unlinkRunFile(); | |
25 | static void setRunFilename(std::string const &newName); | |
26 | ||
27 | static std::string const &runFilename(); | |
28 | ||
29 | }; | |
30 | ||
31 | inline void Lock::setRunFilename(std::string const &newName) | |
32 | { | |
33 | s_runFilename = newName; | |
34 | } | |
35 | ||
36 | inline std::string const &Lock::runFilename() | |
37 | { | |
38 | return s_runFilename; | |
39 | } | |
40 | ||
41 | inline void Lock::unlinkRunFile() | |
42 | { | |
43 | unlink(s_runFilename.c_str()); // s_runFilename may be empty | |
44 | } | |
45 | ||
46 | #endif | |
47 | ||
48 | ||
49 | ||
50 | ||
51 | ||
52 | ||
53 | ||
54 |
0 | #include "lock.h" | |
1 | ||
2 | #include <cstdio> | |
3 | #include <sys/file.h> | |
4 | ||
5 | #include <bobcat/mstream> | |
6 | ||
7 | using namespace std; | |
8 | using namespace FBB; | |
9 |
0 | #include "lock.ih" | |
1 | ||
2 | // In time: make a CFIle object allowing us to open a file, determine its | |
3 | // file descriptor, and have it closed by its destructor. | |
4 | ||
5 | bool Lock::lockRunFile(LockType type) | |
6 | try | |
7 | { | |
8 | // if (s_runFILE) | |
9 | // fmsg << "Internal error: runfile already locked" << endl; | |
10 | // | |
11 | // if (s_runFilename.empty()) // no runfilename, no lock. | |
12 | // { | |
13 | // imsg << "No need to lock a run file" << endl; | |
14 | // return true; | |
15 | // } | |
16 | ||
17 | imsg << "opening `" << s_runFilename << "' for reading" << endl; | |
18 | ||
19 | s_runFILE = fopen(s_runFilename.c_str(), "r"); | |
20 | ||
21 | if (s_runFILE == 0) | |
22 | fmsg << "Can't open run-file `" << s_runFilename.c_str() << '\'' << | |
23 | endl; | |
24 | ||
25 | if (type == BLOCKING) | |
26 | { | |
27 | // imsg << "attempting blocking mode lock" << endl; | |
28 | // if (flock(fileno(s_runFILE), LOCK_EX) == 0) | |
29 | throw true; | |
30 | // imsg << "blocking mode lock FAILED" << endl; | |
31 | } | |
32 | else | |
33 | { | |
34 | imsg << "attempting non-blocking mode lock on FD " << | |
35 | fileno(s_runFILE) << endl; | |
36 | // for (size_t idx = 0; idx < s_maxBlockAttempts; ++idx) | |
37 | // { | |
38 | // if (flock(fileno(s_runFILE), LOCK_EX | LOCK_NB) == 0) | |
39 | throw true; | |
40 | // imsg << '.'; | |
41 | // ::sleep(1); | |
42 | // imsg << "\nNon-blocking mode lock FAILED" << endl; | |
43 | // } | |
44 | } | |
45 | throw false; | |
46 | } | |
47 | catch (bool ret) | |
48 | { | |
49 | imsg << "locked (and return): " << ret << endl; | |
50 | ||
51 | // if (!ret) | |
52 | // fmsg << "Failed to lock run-file `" << s_runFilename << '\'' << endl; | |
53 | ||
54 | return true; | |
55 | } | |
56 | ||
57 | ||
58 |
0 | #include "lock.ih" | |
1 | ||
2 | void Lock::unlockRunFile() | |
3 | { | |
4 | // if (s_runFILE) | |
5 | // { | |
6 | // flock(fileno(s_runFILE), LOCK_UN); | |
7 | // fclose(s_runFILE); // closing removes the lock | |
8 | // } | |
9 | // s_runFILE = 0; | |
10 | } |
0 | #ifndef INCLUDED_LOGUNIT_ | |
1 | #define INCLUDED_LOGUNIT_ | |
2 | ||
3 | #include <memory> | |
4 | #include <ostream> | |
5 | ||
6 | #include <bobcat/multistreambuf> | |
7 | ||
8 | class Options; | |
9 | ||
10 | namespace FBB | |
11 | { | |
12 | class LogBuffer; | |
13 | class Syslogbuf; | |
14 | } | |
15 | ||
16 | class LogUnit | |
17 | { | |
18 | Options &d_options; | |
19 | ||
20 | std::unique_ptr<std::ostream> d_log; | |
21 | std::unique_ptr<std::ostream> d_syslog; | |
22 | ||
23 | std::unique_ptr<FBB::MultiStreambuf> d_imsgbuf; | |
24 | std::unique_ptr<FBB::MultiStreambuf> d_fmsgbuf; | |
25 | ||
26 | public: | |
27 | LogUnit(Options &options); | |
28 | ||
29 | void setupLogs(); | |
30 | void setupLogs(std::ostream &report); | |
31 | ||
32 | std::ostream *newSyslogStream(); | |
33 | std::ostream *newLog(); | |
34 | }; | |
35 | ||
36 | #endif | |
37 | ||
38 | ||
39 | ||
40 |
0 | #include "logunit.h" | |
1 | ||
2 | #include <iostream> | |
3 | ||
4 | #include <bobcat/logbuffer> | |
5 | #include <bobcat/syslogbuf> | |
6 | #include <bobcat/mstream> | |
7 | ||
8 | #include "../options/options.h" | |
9 | ||
10 | using namespace std; | |
11 | using namespace FBB; | |
12 | ||
13 | ||
14 |
0 | #include "logunit.ih" | |
1 | ||
2 | ostream *LogUnit::newLog() | |
3 | try | |
4 | { | |
5 | string const &name = d_options.logName(); | |
6 | ||
7 | return name.empty() ? 0 : new Log(name); | |
8 | } | |
9 | catch (exception const &exc) | |
10 | { | |
11 | fmsg << "cannot write log file `" << d_options.logName() << '\'' << noidl; | |
12 | return 0; // to make the compiler happy | |
13 | } |
0 | #include "logunit.ih" | |
1 | ||
2 | ostream *LogUnit::newSyslogStream() | |
3 | try | |
4 | { | |
5 | SyslogStruct const &info = d_options.syslogStruct(); | |
6 | ||
7 | return info.requested ? | |
8 | new SyslogStream(info.tag, info.priority, info.facility) | |
9 | : | |
10 | 0; | |
11 | } | |
12 | catch (exception const &exc) | |
13 | { | |
14 | fmsg << "cannot write syslog messages" << noidl; | |
15 | return 0; // to make the compiler happy | |
16 | } |
0 | #include "logunit.ih" | |
1 | ||
2 | // If --log was requested, define the logbuffer. | |
3 | // If --syslog was requested define the syslogbuf | |
4 | // If either fails, send fmsg. | |
5 | // | |
6 | // If both succeed messages inserted into imsg (and so: into m1..m3) are sent | |
7 | // to all logfiles; if --stdout has also been specified then imsg also inserts | |
8 | // into cout. | |
9 | // | |
10 | // fmsg, after setuplogs also inserts into the mail, and pending mail is | |
11 | // delivered when the mail object is destroyed. | |
12 | ||
13 | void LogUnit::setupLogs() | |
14 | { | |
15 | unique_ptr<ostream> log(newLog()); | |
16 | ||
17 | unique_ptr<ostream> syslog(newSyslogStream()); | |
18 | ||
19 | unique_ptr<MultiStreambuf> imsgbuf(new MultiStreambuf); | |
20 | ||
21 | if (log.get() != 0) | |
22 | { | |
23 | d_log.swap(log); // install the new Log | |
24 | imsgbuf->insert(*d_log); | |
25 | } | |
26 | ||
27 | if (syslog.get() != 0) | |
28 | { | |
29 | d_syslog.swap(syslog); // install the new syslogbuf | |
30 | imsgbuf->insert(*d_syslog); | |
31 | } | |
32 | ||
33 | if (d_options.stdout()) | |
34 | imsgbuf->insert(cout); | |
35 | ||
36 | if (imsgbuf->begin() != imsgbuf->end()) | |
37 | { | |
38 | d_imsgbuf.swap(imsgbuf); | |
39 | imsg.reset(d_imsgbuf.get()); | |
40 | } | |
41 | ||
42 | unique_ptr<MultiStreambuf> fmsgbuf(new MultiStreambuf); | |
43 | fmsgbuf->insert(imsg); | |
44 | d_fmsgbuf.swap(fmsgbuf); | |
45 | ||
46 | fmsg.reset(d_fmsgbuf.get()); | |
47 | } |
0 | #include "logunit.ih" | |
1 | ||
2 | void LogUnit::setupLogs(ostream &report) | |
3 | { | |
4 | setupLogs(); | |
5 | d_fmsgbuf->insert(report); | |
6 | } |
70 | 70 | longOption, endLongOption, |
71 | 71 | argc, argv); |
72 | 72 | |
73 | arg.versionHelp(Options::usage, Icmbuild::version, 0); | |
73 | arg.versionHelp(Options::usage, Icmbuild::version, 1); | |
74 | 74 | |
75 | 75 | Stealth stealth; |
76 | 76 | |
77 | if (not stealth.contactPeer()) | |
78 | stealth.processPolicy(); // do all policy-file related tasks | |
77 | if (stealth.ipcMode()) | |
78 | return 0; | |
79 | ||
80 | stealth.policyMode(); // do all policy-file related tasks | |
79 | 81 | } |
80 | 82 | catch (exception const &err) |
81 | 83 | { |
82 | if (err.what() != to_string(fmsg.id())) | |
83 | cout << err.what() << '\n'; | |
84 | cout << err.what() << endl; | |
84 | 85 | return 1; |
85 | 86 | } |
86 | 87 | catch (int ret) |
89 | 90 | } |
90 | 91 | catch (...) |
91 | 92 | { |
92 | cerr << "\n" | |
93 | cout << "\n" | |
93 | 94 | "Stealth terminated with an UNEXPECTED EXCEPTION.\n" << |
94 | 95 | "This should not have happened, please report this error and the " |
95 | 96 | "circumstances\n" |
0 | 0 | #include <iostream> |
1 | 1 | |
2 | #include <bobcat/arg> | |
2 | #include <bobcat/argconfig> | |
3 | 3 | #include <bobcat/mstream> |
4 | 4 | |
5 | 5 | #include "options/options.h" |
8 | 8 | Msg(); // msgs are inserted if verbosity <= |
9 | 9 | // the configured verbosity level |
10 | 10 | // E.g., configured: 3 inserts m1, m2 and m3 |
11 | Msg(std::ostream &out); | |
11 | ||
12 | Msg(std::ostream &out); // Used by mp, writing to cout | |
12 | 13 | |
13 | 14 | static void setVerbosity(size_t verbosity); |
14 | 15 | }; |
16 | 16 | } |
17 | 17 | catch (...) |
18 | 18 | { |
19 | fmsg << "Invalid --" << option << " specified" << endl; | |
19 | fmsg << "Invalid --" << option << " specified" << noidl; | |
20 | 20 | return 0; |
21 | 21 | } |
22 | 22 |
25 | 25 | if (d_terminate) |
26 | 26 | fmsg << " --terminate"; |
27 | 27 | |
28 | fmsg << endl; | |
28 | fmsg << noidl; | |
29 | 29 | } |
30 | 30 | } |
31 | 31 |
0 | 0 | #include "options.ih" |
1 | 1 | |
2 | 2 | Options *Options::s_options = 0; |
3 | ||
4 | char const Options::s_configFileBase[] = ".stealth"; // in $HOME | |
5 | 3 | |
6 | 4 | char const Options::s_defaultSyslogIdent[] = "STEALTH"; |
7 | 5 | Facility Options::s_defaultSyslogFacility = Facility::DAEMON; |
3 | 3 | { |
4 | 4 | if (not d_foreground) |
5 | 5 | fmsg << "--" << optionName << " is only valid for a " << |
6 | basename() << " foreground process" << endl; | |
6 | basename() << " foreground process" << noidl; | |
7 | 7 | } |
0 | #include "options.ih" | |
1 | ||
2 | string Options::getCwd() | |
3 | { | |
4 | char buffer[PATH_MAX]; | |
5 | string base(getcwd(buffer, PATH_MAX)); | |
6 | base += '/'; | |
7 | ||
8 | return base; | |
9 | } |
0 | #include "options.ih" | |
1 | ||
2 | Options &Options::instance() | |
3 | { | |
4 | if (s_options == 0) | |
5 | s_options = new Options(); | |
6 | ||
7 | return *s_options; | |
8 | } |
0 | #include "options.ih" | |
1 | ||
2 | void Options::loadPolicyOptions() | |
3 | { | |
4 | if (d_ipc) | |
5 | return; | |
6 | ||
7 | d_policyFilePath = Util::realPath(d_arg[0]); | |
8 | ||
9 | ifstream policy; | |
10 | Exception::open(policy, d_policyFilePath); | |
11 | ||
12 | string line; | |
13 | while (getline(policy, line) && line != "%%") // find the %% separator | |
14 | ; | |
15 | ||
16 | if (line != "%%") // no separator? | |
17 | return; // then done here | |
18 | ||
19 | TempStream tmpStream(User().homedir() + s_configFileBase); | |
20 | ||
21 | tmpStream << policy.rdbuf(); // copy the long options | |
22 | // into the temp. stream | |
23 | ||
24 | tmpStream.close(); | |
25 | ||
26 | d_arg.open(tmpStream.fileName()); // read the config file | |
27 | } | |
28 |
61 | 61 | |
62 | 62 | if (usedKeepAlive or usedSuppress) |
63 | 63 | fmsg << basename() << " V. " << Icmbuild::version << |
64 | " terminated" << endl; | |
64 | " terminated" << noidl; | |
65 | 65 | else |
66 | 66 | wmsg << flush; |
67 | 67 | } |
0 | 0 | #ifndef INCLUDED_OPTIONS_ |
1 | 1 | #define INCLUDED_OPTIONS_ |
2 | 2 | |
3 | #include <memory> | |
3 | #include <string> | |
4 | 4 | |
5 | 5 | #include <bobcat/argconfig> |
6 | 6 | #include <bobcat/linearmap> |
7 | ||
7 | 8 | #include <bobcat/log> |
8 | #include <bobcat/multistreambuf> | |
9 | #include <bobcat/syslogstream> | |
10 | 9 | |
11 | 10 | #include "../stealthenums/stealthenums.h" |
12 | ||
13 | struct Options: public StealthEnums | |
14 | { | |
11 | #include "../syslogstruct/syslogstruct.h" | |
12 | ||
13 | class Options: public StealthEnums | |
14 | { | |
15 | enum FileArgs | |
16 | { | |
17 | LOG = 1 << 0, | |
18 | SKIP_FILE = 1 << 1 | |
19 | }; | |
20 | ||
15 | 21 | FBB::ArgConfig &d_arg; |
16 | 22 | |
17 | std::shared_ptr<FBB::SyslogStream> d_syslog; | |
18 | FBB::Log d_log; | |
19 | ||
20 | FBB::MultiStreambuf d_multiStreambuf; | |
21 | std::ostream d_msg; // d_msg handles all messages to | |
22 | // syslog and/or d_log | |
23 | ||
23 | std::string d_policyPath; | |
24 | ||
24 | 25 | Mode d_mode = INTEGRITY_SCAN; |
25 | 26 | |
26 | std::string d_policyFilePath; | |
27 | std::string d_skipFilePath; | |
28 | std::string d_runFile; | |
27 | std::string d_base; | |
28 | ||
29 | std::string d_skipFile; | |
30 | std::string d_logName; | |
31 | int d_cmdLineOption = 0; | |
32 | ||
33 | std::string d_unixDomainSocket; | |
29 | 34 | std::string d_maxSizeStr; |
30 | 35 | |
31 | 36 | bool d_reload; |
36 | 41 | bool d_daemon; |
37 | 42 | bool d_randomDelay; |
38 | 43 | bool d_sendMail = true; |
39 | bool d_logMail = false; | |
40 | bool d_stdout = false; | |
44 | bool d_logMail = false; | |
45 | bool d_stdout = false; | |
41 | 46 | bool d_repeat; |
42 | 47 | bool d_foreground; |
43 | 48 | bool d_ipc; |
44 | 49 | bool d_dryrun; |
45 | 50 | size_t d_repeatInterval; |
46 | size_t d_delayInterval = 0; | |
47 | size_t d_commandNr = 0; | |
48 | size_t d_parsePolicy = 0; | |
51 | size_t d_delayInterval = 0; | |
52 | size_t d_commandNr = 0; | |
53 | size_t d_parsePolicy = 0; | |
49 | 54 | size_t d_verbosity; |
55 | ||
56 | SyslogStruct d_syslogStruct; | |
57 | ||
50 | 58 | |
51 | 59 | std::streamsize d_maxDownloadSize = 10 * 1024 * 1024; // 10 MB |
52 | 60 | |
59 | 67 | |
60 | 68 | static Options *s_options; |
61 | 69 | |
62 | static char const s_configFileBase[]; | |
63 | 70 | static FBB::Facility s_defaultSyslogFacility; |
64 | 71 | static FBB::Priority s_defaultSyslogPriority; |
65 | 72 | static char const s_defaultSyslogIdent[]; |
74 | 81 | static FBB::LinearMap<Mode, char const *> const s_modeName; |
75 | 82 | |
76 | 83 | public: |
77 | static Options &instance(); | |
84 | Options(); | |
78 | 85 | |
79 | 86 | Options(Options const &other) = delete; |
80 | 87 | |
81 | 88 | void oldOptions() const; |
82 | 89 | |
83 | size_t parsePolicyFile() const; | |
84 | 90 | bool verbose() const; |
85 | 91 | bool ipc() const; |
86 | 92 | bool reload() const; |
91 | 97 | bool daemon() const; |
92 | 98 | bool repeat() const; |
93 | 99 | bool sendMail() const; |
100 | ||
94 | 101 | bool logMail() const; |
102 | void setLogMail(); | |
103 | ||
95 | 104 | bool stdout() const; |
96 | 105 | bool dryrun() const; |
97 | 106 | |
99 | 108 | char const *modeRequest() const; |
100 | 109 | |
101 | 110 | size_t commandNr() const; |
102 | size_t randomAddition() const; | |
103 | size_t repeatInterval() const; | |
111 | size_t nextIntegrityScan() const; | |
112 | ||
113 | size_t parsePolicy() const; | |
104 | 114 | size_t verbosity() const; |
105 | 115 | |
106 | 116 | std::streamsize maxDownloadSize() const; |
107 | 117 | |
108 | 118 | std::string const &basename() const; |
109 | 119 | std::string const &maxSizeStr() const; |
120 | std::string const &unixDomainSocket() const; | |
121 | std::string const &skipFile() const; | |
122 | std::string const &logName() const; | |
110 | 123 | std::string const &policyFilePath() const; |
111 | std::string const &runFile() const; | |
112 | std::string const &skipFilePath() const; | |
113 | 124 | |
114 | 125 | std::string rfc2822() const; |
115 | 126 | |
127 | SyslogStruct const &syslogStruct() const; | |
128 | ||
129 | FBB::TimeStamps timestamp() const; | |
130 | ||
131 | void setConfigOptions(); // set options which may be (re)defined by | |
132 | // config-files (e.g. the 2nd part of | |
133 | // policy files | |
134 | ||
135 | ||
116 | 136 | static void usage(std::string const &progname); |
117 | 137 | |
118 | 138 | private: |
119 | Options(); | |
139 | static std::string getCwd(); | |
120 | 140 | |
121 | 141 | void requireSomeArgument(); |
122 | 142 | |
123 | 143 | void setMode(); |
124 | 144 | void checkMode() const; |
125 | 145 | |
126 | void setTimestamp(); | |
127 | 146 | void setCommandNr(); |
128 | 147 | void setParsePolicy(); |
148 | ||
129 | 149 | void setStdout(); |
130 | std::string setLog(); | |
150 | ||
151 | int setLog(); // initially using cmd-line options | |
152 | int setSkipFile(); // when set in the policy file use the | |
153 | // policy file's base | |
154 | ||
155 | void setTimestamp(); | |
131 | 156 | |
132 | 157 | void setRepeat(); |
133 | 158 | void setRandomDelay(); |
134 | 159 | size_t checkM(std::string const &spec, char const *option) const; |
135 | 160 | |
161 | size_t randomAddition() const; | |
162 | size_t repeatInterval() const; | |
163 | ||
136 | 164 | void setMail(); |
137 | void setSkipFilePath(); | |
138 | 165 | void setDownloadSize(); |
139 | void setVerbosity(bool useSyslog, std::string const &logName); | |
140 | ||
141 | bool setSyslog(); | |
142 | ||
143 | std::string syslogTag() const; | |
144 | FBB::Priority syslogPriority() const; | |
145 | FBB::Facility syslogFacility() const; | |
146 | ||
147 | ||
148 | void loadPolicyOptions(); | |
166 | ||
167 | void setVerbosity(); | |
168 | ||
169 | void setSyslog(); | |
170 | void setSyslogPriority(); | |
171 | void setSyslogFacility(); | |
172 | ||
173 | void setPolicyPath(); | |
149 | 174 | |
150 | 175 | void foregroundOnly(char const *optionName) const; |
151 | 176 | }; |
152 | 177 | |
178 | inline FBB::TimeStamps Options::timestamp() const | |
179 | { | |
180 | return d_timestamp; | |
181 | } | |
182 | ||
183 | inline SyslogStruct const &Options::syslogStruct() const | |
184 | { | |
185 | return d_syslogStruct; | |
186 | } | |
187 | ||
153 | 188 | inline size_t Options::verbosity() const |
154 | 189 | { |
155 | 190 | return d_verbosity; |
156 | 191 | } |
157 | 192 | |
193 | inline size_t Options::parsePolicy() const | |
194 | { | |
195 | return d_parsePolicy; | |
196 | } | |
197 | ||
158 | 198 | inline Options::Mode Options::mode() const |
159 | 199 | { |
160 | 200 | return d_mode; |
175 | 215 | return d_logMail; |
176 | 216 | } |
177 | 217 | |
218 | inline void Options::setLogMail() | |
219 | { | |
220 | d_logMail = true; | |
221 | } | |
222 | ||
178 | 223 | inline bool Options::reload() const |
179 | 224 | { |
180 | 225 | return d_reload; |
185 | 230 | return d_arg.option('V'); |
186 | 231 | } |
187 | 232 | |
188 | inline size_t Options::parsePolicyFile() const | |
189 | { | |
190 | return d_parsePolicy; | |
191 | } | |
192 | ||
193 | 233 | inline bool Options::rerun() const |
194 | 234 | { |
195 | 235 | return d_rerun; |
237 | 277 | |
238 | 278 | inline std::string const &Options::policyFilePath() const |
239 | 279 | { |
240 | return d_policyFilePath; | |
241 | } | |
242 | ||
243 | inline std::string const &Options::skipFilePath() const | |
244 | { | |
245 | return d_skipFilePath; | |
246 | } | |
247 | ||
248 | inline std::string const &Options::runFile() const | |
249 | { | |
250 | return d_runFile; | |
280 | return d_policyPath; | |
281 | } | |
282 | ||
283 | inline std::string const &Options::skipFile() const | |
284 | { | |
285 | return d_skipFile; | |
286 | } | |
287 | ||
288 | inline std::string const &Options::logName() const | |
289 | { | |
290 | return d_logName; | |
291 | } | |
292 | ||
293 | inline std::string const &Options::unixDomainSocket() const | |
294 | { | |
295 | return d_unixDomainSocket; | |
251 | 296 | } |
252 | 297 | |
253 | 298 | inline std::string const &Options::basename() const |
260 | 305 | return d_repeatInterval; |
261 | 306 | } |
262 | 307 | |
308 | inline size_t Options::nextIntegrityScan() const | |
309 | { | |
310 | return repeatInterval() + randomAddition(); | |
311 | } | |
312 | ||
263 | 313 | inline size_t Options::commandNr() const |
264 | 314 | { |
265 | 315 | return d_commandNr; |
1 | 1 | |
2 | 2 | #include <iostream> |
3 | 3 | #include <sstream> |
4 | #include <string> | |
5 | #include <cstdlib> | |
6 | #include <unistd.h> | |
7 | #include <csignal> | |
8 | 4 | |
9 | #include <bobcat/user> | |
10 | 5 | #include <bobcat/mstream> |
11 | #include <bobcat/tempstream> | |
12 | #include <bobcat/exception> | |
13 | 6 | #include <bobcat/datetime> |
14 | 7 | |
15 | 8 | #include "../msg/msg.h" |
0 | 0 | #include "options.ih" |
1 | ||
2 | // No log-files are available yet. But since Options is constructed while | |
3 | // stealth runs in the foreground, error messages can be sent to cerr. | |
1 | 4 | |
2 | 5 | Options::Options() |
3 | 6 | : |
4 | 7 | d_arg(ArgConfig::instance()), |
5 | d_msg(&d_multiStreambuf), | |
8 | d_base(getCwd()), | |
6 | 9 | d_maxSizeStr("10M"), |
7 | 10 | d_repeatInterval(numeric_limits<int>::max()) |
8 | 11 | { |
12 | ||
9 | 13 | requireSomeArgument(); // no args/options, then usage and ends. |
10 | 14 | |
11 | 15 | oldOptions(); // ends if --keep-alive or --suppress was |
17 | 21 | |
18 | 22 | d_dryrun = d_arg.option(0, "dry-run"); |
19 | 23 | |
24 | // preset file name options when defined as | |
25 | // command-line options, using base = cwd | |
26 | d_cmdLineOption = setLog() | setSkipFile(); | |
27 | ||
20 | 28 | setCommandNr(); // sets run-command, (requires foreground). |
21 | 29 | setParsePolicy(); // sets the policy file (requires foreground) |
22 | ||
23 | loadPolicyOptions(); // load any configuration options from the | |
24 | // policy file into ArgConfig | |
25 | 30 | |
26 | setMail(); // sets log-mail and no-mail | |
27 | setSkipFilePath(); | |
31 | setPolicyPath(); | |
28 | 32 | |
29 | setTimestamp(); | |
33 | if (d_daemon) | |
34 | { | |
35 | Util::absPath(d_base, d_unixDomainSocket); | |
30 | 36 | |
31 | setVerbosity( setSyslog(), setLog() ); | |
37 | if (access(d_unixDomainSocket.c_str(), F_OK) == 0) | |
38 | fmsg << "Unix Domain Socket `" << d_unixDomainSocket << | |
39 | "': already in use, remove it first" << noidl; | |
40 | } | |
32 | 41 | |
33 | setStdout(); | |
34 | setRepeat(); | |
35 | setRandomDelay(); | |
36 | setDownloadSize(); | |
42 | setConfigOptions(); | |
37 | 43 | |
38 | if (not d_ipc) | |
39 | m1 << "timestamps use " << | |
40 | (d_timestamp == TIMESTAMPS ? "local time" : "UTC") << endl; | |
44 | if | |
45 | ( | |
46 | not d_skipFile.empty() | |
47 | and | |
48 | access(d_skipFile.c_str(), R_OK) != 0 | |
49 | ) | |
50 | fmsg << "Can't read skip-file `" << d_skipFile << '\'' << noidl; | |
51 | ||
52 | ||
41 | 53 | } |
42 | 54 | |
43 | 55 |
12 | 12 | d_commandNr = stoul(value); |
13 | 13 | if (d_commandNr == 0) |
14 | 14 | fmsg << "--run-command 0: not a valid (natural) command number" << |
15 | endl; | |
15 | noidl; | |
16 | 16 | if (not d_stdout) |
17 | { | |
18 | 17 | d_stdout = true; |
19 | d_multiStreambuf.insert(cout); | |
20 | } | |
21 | 18 | } |
22 | 19 | catch (...) |
23 | 20 | { |
24 | 21 | d_commandNr = 0; |
25 | 22 | fmsg << "--run-command " << value << ": invalid command number" << |
26 | endl; | |
23 | noidl; | |
27 | 24 | } |
28 | 25 | } |
29 | 26 |
0 | #include "options.ih" | |
1 | ||
2 | void Options::setConfigOptions() | |
3 | { | |
4 | setMail(); // sets log-mail and no-mail | |
5 | setSkipFile(); | |
6 | ||
7 | setLog(); | |
8 | setTimestamp(); | |
9 | ||
10 | setSyslog(); | |
11 | ||
12 | setVerbosity(); | |
13 | setStdout(); | |
14 | ||
15 | setRepeat(); | |
16 | setRandomDelay(); | |
17 | setDownloadSize(); | |
18 | } |
5 | 5 | return; |
6 | 6 | |
7 | 7 | if (d_ipc) |
8 | fmsg << "--max-size incompatible with IPC calls" << endl; | |
8 | fmsg << "--max-size incompatible with IPC calls" << noidl; | |
9 | 9 | |
10 | 10 | size_t pos; |
11 | 11 | try |
35 | 35 | catch (...) |
36 | 36 | {} |
37 | 37 | |
38 | fmsg << "--max-size " << d_maxSizeStr << ": invalid option value" << endl; | |
38 | fmsg << "--max-size " << d_maxSizeStr << ": invalid option value" << | |
39 | noidl; | |
39 | 40 | } |
40 | 41 | |
41 | 42 |
0 | 0 | #include "options.ih" |
1 | 1 | |
2 | string Options::setLog() | |
2 | int Options::setLog() | |
3 | 3 | { |
4 | string logName; | |
5 | if (d_arg.option(&logName, 'L')) | |
6 | { | |
7 | d_log.open(logName); | |
8 | if (not d_log) | |
9 | fmsg << "could not open " << logName << endl; | |
4 | if | |
5 | ( | |
6 | (d_cmdLineOption & LOG) // already a command line option | |
7 | or | |
8 | not d_arg.option(&d_logName, 'L') | |
9 | ) | |
10 | return 0; | |
10 | 11 | |
11 | d_log.setTimestamp(d_timestamp); | |
12 | ||
13 | d_multiStreambuf.insert(d_log); | |
14 | } | |
15 | return logName; | |
12 | Util::absPath(d_base, d_logName); | |
13 | return LOG; | |
16 | 14 | } |
16 | 16 | if ((d_resume = d_arg.option(0, "resume"))) |
17 | 17 | d_mode = RESUME; |
18 | 18 | |
19 | if | |
20 | ( | |
21 | (d_daemon = d_arg.option(&d_runFile, 'd')) | |
22 | and | |
23 | d_runFile[0] != '/' | |
19 | if ( | |
20 | (d_daemon = d_arg.option(&d_unixDomainSocket, 'd')) | |
21 | && | |
22 | (d_arg.nArgs() == 0) | |
24 | 23 | ) |
25 | { | |
26 | if (d_arg.nArgs() == 0) | |
27 | fmsg << "--daemon: missing run-file or policy file" << endl; | |
28 | else | |
29 | fmsg << "--daemon: " << d_runFile << | |
30 | ": must use an absolute file name" << endl; | |
31 | } | |
32 | ||
33 | if (d_mode & (RELOAD | RERUN | TERMINATE | SUSPEND | RESUME)) | |
34 | d_runFile = d_arg[0]; | |
24 | fmsg << "--daemon: missing Unix Domain File or policy file" << noidl; | |
35 | 25 | |
36 | 26 | d_ipc = d_reload || d_rerun || d_terminate || d_suspend || d_resume; |
37 | 27 | |
28 | if (d_ipc) | |
29 | d_unixDomainSocket = d_arg[0]; | |
30 | ||
38 | 31 | d_foreground = not d_ipc and not d_daemon; |
39 | 32 | } |
0 | #include "options.ih" | |
1 | ||
2 | void Options::setPolicyPath() | |
3 | { | |
4 | if (d_ipc) | |
5 | return; | |
6 | ||
7 | d_policyPath = d_arg[0]; | |
8 | ||
9 | Util::absPath(d_base, d_policyPath); | |
10 | } |
8 | 8 | return; |
9 | 9 | |
10 | 10 | if (not d_repeat) |
11 | fmsg << "--random-interval requires --repeat" << endl; | |
11 | fmsg << "--random-interval requires --repeat" << noidl; | |
12 | 12 | |
13 | 13 | d_delayInterval = checkM(delay, "random-interval"); |
14 | 14 |
7 | 7 | return; |
8 | 8 | |
9 | 9 | if (d_ipc) |
10 | fmsg << "--repeat not available in IPC modes" << endl; | |
10 | fmsg << "--repeat not available in IPC modes" << noidl; | |
11 | 11 | |
12 | 12 | d_repeatInterval = checkM(value, "repeat"); |
13 | 13 |
0 | #include "options.ih" | |
1 | ||
2 | int Options::setSkipFile() | |
3 | { | |
4 | if ((d_cmdLineOption & SKIP_FILE) or not d_arg.option(&d_skipFile, 's')) | |
5 | return 0; | |
6 | ||
7 | if (d_arg.nArgs() == 0) | |
8 | fmsg << "--skip-files: missing skip-file or policy file" << noidl; | |
9 | ||
10 | if (d_ipc) | |
11 | fmsg << "--skip-files incompatible with IPC calls" << noidl; | |
12 | ||
13 | Util::absPath(d_base, d_skipFile); | |
14 | ||
15 | return SKIP_FILE; | |
16 | } |
0 | #include "options.ih" | |
1 | ||
2 | void Options::setSkipFilePath() | |
3 | { | |
4 | if (not d_arg.option(&d_skipFilePath, 's')) | |
5 | return; | |
6 | ||
7 | if (d_arg.nArgs() == 0) | |
8 | fmsg << "--skip-files: missing skip-file or policy file" << endl; | |
9 | ||
10 | if (d_skipFilePath[0] != '/') | |
11 | fmsg << "--skip-files " << d_skipFilePath << | |
12 | ": must specify an absolute file name" << endl; | |
13 | ||
14 | if (d_ipc) | |
15 | fmsg << "--skip-files incompatible with IPC calls" << endl; | |
16 | } |
4 | 4 | if (d_arg.option('o') or d_ipc) |
5 | 5 | { |
6 | 6 | if (d_daemon) |
7 | fmsg << "--stdout incompatible with --daemon" << endl; | |
7 | fmsg << "--stdout incompatible with --daemon" << noidl; | |
8 | 8 | |
9 | 9 | d_stdout = true; |
10 | d_multiStreambuf.insert(cout); | |
11 | 10 | } |
12 | 11 | } |
0 | 0 | #include "options.ih" |
1 | 1 | |
2 | bool Options::setSyslog() | |
2 | void Options::setSyslog() | |
3 | 3 | { |
4 | if (not d_arg.option(0, "syslog")) | |
5 | return false; | |
4 | d_syslogStruct.requested = d_arg.option(0, "syslog"); | |
5 | ||
6 | if (not d_syslogStruct.requested) | |
7 | return; | |
6 | 8 | |
7 | 9 | if (d_ipc) |
8 | fmsg << "--syslog* options incompatible with IPC calls" << endl; | |
10 | fmsg << "--syslog* options incompatible with IPC calls" << noidl; | |
9 | 11 | |
10 | d_syslog = make_shared<SyslogStream>(syslogTag(), syslogPriority(), | |
11 | syslogFacility()); | |
12 | 12 | |
13 | d_multiStreambuf.insert(*d_syslog); | |
14 | return true; | |
13 | if (not d_arg.option(&d_syslogStruct.tag, "syslog-tag")) | |
14 | d_syslogStruct.tag = s_defaultSyslogIdent; | |
15 | ||
16 | setSyslogPriority(); | |
17 | setSyslogFacility(); | |
15 | 18 | } |
0 | #include "options.ih" | |
1 | ||
2 | void Options::setSyslogFacility() | |
3 | { | |
4 | string option; | |
5 | if (not d_arg.option(&option, "syslog-facility")) | |
6 | d_syslogStruct.facility = s_defaultSyslogFacility; | |
7 | else | |
8 | { | |
9 | LinearMap<string, Facility>::const_iterator | |
10 | iter = s_syslogFacilities.find(option); | |
11 | ||
12 | if (iter == s_syslogFacilities.end()) | |
13 | fmsg << "syslog facility " << option << " not supported" << noidl; | |
14 | ||
15 | d_syslogStruct.facility = iter->second; | |
16 | } | |
17 | } | |
18 |
0 | #include "options.ih" | |
1 | ||
2 | void Options::setSyslogPriority() | |
3 | { | |
4 | string option; | |
5 | if (not d_arg.option(&option, "syslog-priority")) | |
6 | d_syslogStruct.priority = s_defaultSyslogPriority; | |
7 | else | |
8 | { | |
9 | LinearMap<std::string, Priority>::const_iterator | |
10 | iter = s_syslogPriorities.find(option); | |
11 | ||
12 | if (iter == s_syslogPriorities.end()) | |
13 | fmsg << "syslog priority " << option << " not supported" << noidl; | |
14 | ||
15 | d_syslogStruct.priority = iter->second; | |
16 | } | |
17 | } | |
18 |
7 | 7 | |
8 | 8 | if (value == "LT") |
9 | 9 | d_timestamp = TIMESTAMPS; |
10 | else if (value == "UTC") | |
11 | d_timestamp = UTCTIMESTAMPS; | |
10 | 12 | else if (value != "UTC") |
11 | 13 | wmsg << "--time-stamp " << value << " not supported. Using UTC" << |
12 | 14 | endl; |
0 | 0 | #include "options.ih" |
1 | 1 | |
2 | void Options::setVerbosity(bool useSyslog, string const &logName) | |
2 | void Options::setVerbosity() | |
3 | 3 | { |
4 | 4 | string verbosity; |
5 | bool verb; | |
6 | d_verbosity = (verb = d_arg.option(&verbosity, 'V')) ? | |
5 | ||
6 | d_verbosity = (d_arg.option(&verbosity, 'V')) ? | |
7 | 7 | stoul(verbosity) |
8 | 8 | : |
9 | 9 | s_defaultVerbosity; |
10 | ||
11 | if (useSyslog || logName.length() != 0) | |
12 | imsg.reset(d_msg); | |
13 | 10 | |
14 | 11 | Msg::setVerbosity(d_verbosity); |
15 | 12 | } |
0 | #include "options.ih" | |
1 | ||
2 | Facility Options::syslogFacility() const | |
3 | { | |
4 | Facility facility; | |
5 | ||
6 | string option; | |
7 | if (not d_arg.option(&option, "syslog-facility")) | |
8 | facility = s_defaultSyslogFacility; | |
9 | else | |
10 | { | |
11 | LinearMap<string, Facility>::const_iterator | |
12 | iter = s_syslogFacilities.find(option); | |
13 | ||
14 | if (iter == s_syslogFacilities.end()) | |
15 | fmsg << "syslog facility " << option << " not supported" << endl; | |
16 | ||
17 | facility = iter->second; | |
18 | } | |
19 | ||
20 | return facility; | |
21 | } | |
22 |
0 | #include "options.ih" | |
1 | ||
2 | Priority Options::syslogPriority() const | |
3 | { | |
4 | Priority priority; | |
5 | ||
6 | string option; | |
7 | if (not d_arg.option(&option, "syslog-priority")) | |
8 | priority = s_defaultSyslogPriority; | |
9 | else | |
10 | { | |
11 | LinearMap<std::string, Priority>::const_iterator | |
12 | iter = s_syslogPriorities.find(option); | |
13 | ||
14 | if (iter == s_syslogPriorities.end()) | |
15 | fmsg << "syslog priority " << option << " not supported" << endl; | |
16 | ||
17 | priority = iter->second; | |
18 | } | |
19 | ||
20 | return priority; | |
21 | } | |
22 |
0 | #include "options.ih" | |
1 | ||
2 | string Options::syslogTag() const | |
3 | { | |
4 | string tag; | |
5 | if (not d_arg.option(&tag, "syslog-tag")) | |
6 | tag = s_defaultSyslogIdent; | |
7 | return tag; | |
8 | } |
16 | 16 | "the\n" |
17 | 17 | " policy file).\n" |
18 | 18 | |
19 | " --daemon (-d) <path>: (C) run as a background (daemon) process.\n" | |
20 | " <path> is the absolute filename of a pid-file used for\n" | |
21 | " communication with the stealth daemon process\n" | |
19 | " --daemon (-d) <uds>: (C) run as a background (daemon) process.\n" | |
20 | " <uds> is the location of the Unix Domain Socket that is\n" | |
21 | " used for communication with the stealth daemon process\n" | |
22 | 22 | |
23 | 23 | " --dry-run: (C) no integrity scans or reloads are performed, but\n" |
24 | 24 | " are assumed OK. Remaining tasks are normally performed\n" |
25 | 25 | |
26 | " --log (-L) path: log messages are appended to `path'. If path\n" | |
27 | " does not exist, it is first created \n" | |
26 | " --log (-L) <file-spec>: log messages are appended to " | |
27 | "`<file-spec>'.\n" | |
28 | " If <file-spec> does not exist, it is first created \n" | |
28 | 29 | |
29 | " --logmail: mail is loggeed (requires --log or --syslog)\n" | |
30 | " --logmail: mail is logged (requires --log or --syslog)\n" | |
30 | 31 | |
31 | 32 | " --max-size value[BKMG]: files retrieved by GET may at most\n" |
32 | " have `value' bytes (B), Kbytes (K), Mbytes (M), " | |
33 | " have `value' bytes (B), Kbytes (K), Mbytes (M), " | |
33 | 34 | "Gbytes (G).\n" |
34 | " By default: 10M; The default unit is `B'\n" | |
35 | " By default: 10M; The default unit is `B'\n" | |
35 | 36 | |
36 | 37 | " --no-mail: mail is not sent. By default mail is sent as " |
37 | 38 | "configured\n" |
38 | " in the policy-file (--logmail can be specified " | |
39 | " in the policy-file (--logmail can be specified " | |
39 | 40 | "independently\n" |
40 | " from --no-mail)\n" | |
41 | " from --no-mail)\n" | |
41 | 42 | |
42 | 43 | " --parse-policy-file (-p): (C) parse the policy file, no further " |
43 | 44 | "actions.\n" |
44 | " Specify once to see the numbered commands,\n" | |
45 | " twice to see the policy file parsing steps as well.\n" | |
46 | " Results to std output.\n" | |
45 | " Specify once to see the numbered commands,\n" | |
46 | " twice to see the policy file parsing steps as well.\n" | |
47 | " Results to std output.\n" | |
47 | 48 | |
48 | 49 | " --random-interval (-i) value: start integrity scans within\n" |
49 | " a random interval of `value' seconds (minutes\n" | |
50 | " if an `m' is appended to the specified value).\n" | |
51 | " Requires --repeat.\n" | |
50 | " a random interval of `value' seconds (minutes if an `m'\n" | |
51 | " is appended to the specified value).\n" | |
52 | " Requires --repeat.\n" | |
52 | 53 | |
53 | 54 | " --repeat value: start an integrity scan every `value' seconds\n" |
54 | " (minutes if an `m' is appended to the specified " | |
55 | "value).\n" | |
55 | " (minutes if an `m' is appended to the specified value).\n" | |
56 | 56 | |
57 | 57 | " --run-command (-r) value: (C) only execute command #`value'\n" |
58 | " (not available in combination with --daemon)\n" | |
58 | 59 | |
59 | " --skip-files (-s) path: skip the integrity checks of the\n" | |
60 | " files having their absolute path names listed in " | |
61 | "`path'\n" | |
60 | " --skip-files (-s) <file-spec>: skip the integrity checks of the\n" | |
61 | " files having their absolute path names listed in " | |
62 | "`<file-spec>'\n" | |
62 | 63 | |
63 | " --stdout (-o): messages are (also) written to stdout " | |
64 | "(incompatible\n" | |
65 | " with the --daemon option)\n" | |
64 | " --stdout (-o): messages are (also) written to stdout\n" | |
65 | " (not available in combination with --daemon)\n" | |
66 | 66 | |
67 | 67 | " --syslog: write syslog messages\n" |
68 | 68 | |
69 | 69 | " --syslog-facility fac: syslog facility to use. By default " |
70 | "DAEMON\n" | |
70 | "DAEMON\n" | |
71 | 71 | |
72 | 72 | " --syslog-priority pri: syslog priority to use. By default " |
73 | "NOTICE\n" | |
73 | "NOTICE\n" | |
74 | 74 | |
75 | 75 | " --syslog-tag tag: identifier prefixed to syslog messages. By\n" |
76 | " default `" << s_defaultSyslogIdent << "')\n" | |
76 | " default `" << s_defaultSyslogIdent << "')\n" | |
77 | 77 | |
78 | 78 | " --time-stamp <type>: the time-stamps to use. By default UTC.\n" |
79 | " (does not apply to syslog-timestamps)\n" | |
79 | " (does not apply to syslog-timestamps)\n" | |
80 | 80 | |
81 | 81 | " --verbosity (-V) value: determines the amount of logged " |
82 | 82 | "information.\n" |
83 | " Requires --log or --syslog:\n" | |
84 | " 0: nothing is logged\n" | |
85 | " 1: mode reports and policy commands\n" | |
86 | " 2: also: ipc commands and actions\n" | |
87 | " 3: also: integrity scan informative messages\n" | |
83 | " Requires --log or --syslog:\n" | |
84 | " 0: nothing is logged\n" | |
85 | " 1: mode reports and policy commands\n" | |
86 | " 2: also: ipc commands and actions\n" | |
87 | " 3: also: integrity scan informative messages\n" | |
88 | 88 | |
89 | " policy: path to the policy file\n" | |
89 | " policy: location of the policy file\n" | |
90 | 90 | "\n" |
91 | 91 | |
92 | 92 | "Usage 2 (IPC modes, all options are command-line only):\n" |
93 | 93 | " " << progname << |
94 | " {--reload,--rerun,--resume,--suspend,--terminate} pid-file\n" | |
94 | " {--reload,--rerun,--resume,--suspend,--terminate} <uds>\n" | |
95 | 95 | "Where:\n" |
96 | 96 | " --reload: reload a " << progname << " process's policy and " |
97 | "skip-files\n" | |
97 | "skip-file\n" | |
98 | 98 | " files\n" |
99 | 99 | " --rerun: start an integrity scan\n" |
100 | 100 | " --resume: resume " << progname << " after --suspend\n" |
101 | 101 | " --suspend: suspend " << progname << "'s activities\n" |
102 | 102 | " to continue: --resume; to end: --terminate\n" |
103 | 103 | " --terminate: terminate the " << progname << " daemon\n" |
104 | " pidfile: file containing the pid of the stealth daemon process.\n" | |
104 | " <uds>: location of the Unix Domain Socket to connect to.\n" | |
105 | 105 | "\n" |
106 | 106 | "Usage 3 (support mode, all options are command-line only)\n" |
107 | 107 | " " << progname << " {--help,--version}\n" |
0 | #include "policyfile.ih" | |
1 | ||
2 | void PolicyFile::chdirBase() const | |
3 | { | |
4 | char const *base = d_use.find("BASE")->second.c_str(); | |
5 | ||
6 | if (chdir(base) != 0) | |
7 | fmsg << "Can't chdir to `" << base << '\'' << noidl; | |
8 | } | |
9 |
0 | 0 | #include "policyfile.ih" |
1 | ||
2 | char const PolicyFile::s_configFileBase[] = ".stealth"; // in $HOME | |
1 | 3 | |
2 | 4 | pair<string, string> const |
3 | 5 | PolicyFile::s_defaultKeyword[] = |
22 | 24 | // [0]: all text, |
23 | 25 | // [1]: all ${NAME} text |
24 | 26 | // [2]: NAME itself |
27 | Pattern PolicyFile::s_log( | |
28 | "^\\s*" | |
29 | "(LOCAL\\s+)?" // 1 | |
30 | "(NOTEST\\s+)?" // 2 | |
31 | "CHECK\\s+(LOG\\s*=\\s*)?" // 3 | |
32 | "(\\S+)"); // 4: name of the logfile | |
25 | 33 |
0 | 0 | #include "policyfile.ih" |
1 | 1 | |
2 | 2 | void PolicyFile::directivesAndCommands() |
3 | try | |
3 | 4 | { |
4 | for (int idx = 0, size = d_configfile.size(); idx != size; ++idx) | |
5 | ConfigFile configfile(d_options.policyFilePath()); | |
6 | ||
7 | for (size_t idx = 0, size = configfile.size(); idx != size; ++idx) | |
5 | 8 | { |
6 | string line = d_configfile[idx]; | |
9 | string line = configfile[idx]; | |
7 | 10 | |
8 | if (line == "%%") // stop at section 2 | |
11 | if (line == "%%") | |
9 | 12 | { |
10 | mp << "Policy file processing ends at section 2, line " << | |
11 | (idx + 1) << endl; | |
13 | loadOptions(configfile, idx + 1); | |
12 | 14 | return; |
13 | 15 | } |
14 | 16 | |
30 | 32 | } |
31 | 33 | } |
32 | 34 | } |
33 | ||
35 | catch (exception const &exc) | |
36 | { | |
37 | fmsg << exc.what() << noidl; | |
38 | } |
4 | 4 | void PolicyFile::fetchCommands() |
5 | 5 | { |
6 | 6 | directivesAndCommands(); |
7 | ||
8 | string &base = d_use["BASE"]; | |
9 | ||
10 | if (base.back() != '/') | |
11 | base += '/'; | |
7 | 12 | |
8 | 13 | bool ok = d_use.count("SSH"); |
9 | 14 | |
16 | 21 | for(auto &entry: d_command) |
17 | 22 | replaceDefines(entry); |
18 | 23 | |
19 | if (size_t parse = Options::instance().parsePolicyFile()) | |
24 | fixRelativeLocations(); | |
25 | ||
26 | if (size_t parseOnly = d_options.parsePolicy()) | |
20 | 27 | { |
21 | if (parse > 1) | |
28 | if (parseOnly > 1) | |
29 | { | |
22 | 30 | for(auto &value: d_use) |
23 | 31 | mp << "USE " << value.first << ": " << value.second << endl; |
32 | } | |
24 | 33 | |
25 | 34 | mp.clear(); |
35 | ||
36 | mp << "REPORT: " << d_use["REPORT"] << endl; | |
37 | ||
26 | 38 | for (size_t idx = 0; idx != d_command.size(); ++idx) |
27 | 39 | mp << (idx + 1) << ": " << d_command[idx] << endl; |
28 | 40 | |
30 | 42 | } |
31 | 43 | |
32 | 44 | if (!ok) |
33 | fmsg << "USE SSH ... entry missing in the policy file" << endl; | |
45 | fmsg << "USE SSH ... entry missing in the policy file" << noidl; | |
34 | 46 | } |
35 | 47 | |
48 | ||
49 | ||
50 | ||
51 | ||
52 |
0 | #include "policyfile.ih" | |
1 | ||
2 | void PolicyFile::fixRelativeLocations() | |
3 | { | |
4 | string const &base = d_use["BASE"]; | |
5 | ||
6 | Util::absPath(base, d_use["REPORT"]); | |
7 | ||
8 | for (auto &line: d_command) | |
9 | { | |
10 | // [LOCAL] CHECK [LOG =] <logfile> [pathOffset] <command> | |
11 | // [LOCAL] NOTEST CHECK <logfile> [pathOffset] <command> | |
12 | // NOTEST CHECK [LOG =] <logfile> [pathOffset] <command> | |
13 | ||
14 | if (s_log << line) | |
15 | { | |
16 | string logName = s_log[4]; | |
17 | Pattern::Position pos = s_log.position(4); | |
18 | ||
19 | Util::absPath(base, logName); | |
20 | ||
21 | line.replace(pos.first, pos.second - pos.first, logName); | |
22 | } | |
23 | } | |
24 | } | |
25 | ||
26 | ||
27 | ||
28 | ||
29 |
0 | #include "policyfile.ih" | |
1 | ||
2 | void PolicyFile::load() | |
3 | { | |
4 | d_use = LinearMap( | |
5 | &s_defaultKeyword[0], &s_defaultKeyword[s_nDefaultKeywords] | |
6 | ); | |
7 | ||
8 | d_define.clear(); | |
9 | d_command.clear(); | |
10 | ||
11 | fetchCommands(); | |
12 | ||
13 | string &base = d_use["BASE"]; | |
14 | ||
15 | base += '.'; // the . is required by mkdir | |
16 | char const *cp = base.c_str(); | |
17 | Util::mkdir(cp); | |
18 | base.pop_back(); // cut off the . again | |
19 | ||
20 | chdirBase(); // change to the base directory | |
21 | } | |
22 | ||
23 | ||
24 | ||
25 | ||
26 | ||
27 | ||
28 |
0 | #include "policyfile.ih" | |
1 | ||
2 | void PolicyFile::loadOptions(ConfigFile &configFile, size_t from) | |
3 | { | |
4 | TempStream tmpStream(User().homedir() + s_configFileBase); | |
5 | ||
6 | for | |
7 | ( | |
8 | auto begin = configFile.begin() + from, end = configFile.end(); | |
9 | begin != end; | |
10 | ++begin | |
11 | ) | |
12 | tmpStream << *begin << '\n'; // copy the long options | |
13 | // into the temp. stream | |
14 | ||
15 | tmpStream.close(); | |
16 | ||
17 | // read the config file's options | |
18 | ArgConfig::instance().open(tmpStream.fileName()); | |
19 | ||
20 | d_options.setConfigOptions(); | |
21 | } | |
22 |
3 | 3 | #include <string> |
4 | 4 | #include <vector> |
5 | 5 | #include <bobcat/linearmap> |
6 | #include <bobcat/configfile> | |
6 | ||
7 | class Options; | |
7 | 8 | |
8 | 9 | namespace FBB |
9 | 10 | { |
10 | 11 | class Pattern; |
12 | class ConfigFile; | |
11 | 13 | } |
12 | 14 | |
13 | 15 | class PolicyFile |
14 | 16 | { |
15 | typedef FBB::LinearMap<std::string, std::string> LinearMap; | |
17 | typedef FBB::LinearMap<std::string, std::string> LinearMap; | |
16 | 18 | |
17 | std::string d_policyPath; | |
18 | FBB::ConfigFile d_configfile; | |
19 | std::vector<std::string> d_command; | |
19 | Options &d_options; | |
20 | 20 | |
21 | LinearMap d_use; | |
22 | LinearMap d_define; | |
23 | ||
24 | static std::pair<std::string, std::string> const s_defaultKeyword[]; | |
25 | static size_t s_nDefaultKeywords; | |
26 | static FBB::Pattern s_firstWord; | |
27 | static FBB::Pattern s_comment; | |
28 | static FBB::Pattern s_define; // [0]: all text, | |
29 | // [1]: all ${NAME} text | |
30 | // [2]: NAME itself | |
21 | std::vector<std::string> d_command; | |
22 | ||
23 | LinearMap d_use; | |
24 | LinearMap d_define; | |
25 | ||
26 | static char const s_configFileBase[]; | |
27 | ||
28 | static std::pair<std::string, std::string> const s_defaultKeyword[]; | |
29 | static size_t s_nDefaultKeywords; | |
30 | ||
31 | static FBB::Pattern s_firstWord; | |
32 | static FBB::Pattern s_comment; | |
33 | static FBB::Pattern s_define; // [0]: all text, | |
34 | // [1]: all ${NAME} text | |
35 | // [2]: NAME itself | |
36 | static FBB::Pattern s_log; // [4]: name of the logfile | |
37 | ||
31 | 38 | public: |
32 | PolicyFile(std::string const &policyPath); | |
33 | ||
34 | void reload(); | |
39 | PolicyFile(Options &options); | |
35 | 40 | |
36 | 41 | size_t size() const; |
37 | 42 | std::vector<std::string>::const_iterator firstCmd() const; |
38 | 43 | std::vector<std::string>::const_iterator beyondCmd() const; |
44 | ||
39 | 45 | std::string const &operator[](std::string const &key) const; |
40 | ||
46 | ||
47 | void chdirBase() const; | |
48 | ||
41 | 49 | private: |
50 | void load(); | |
51 | void loadOptions(FBB::ConfigFile &configFile, size_t from); | |
52 | ||
42 | 53 | std::string const &getDEFINE(std::string const &key) const; |
43 | 54 | bool hasDEFINE(std::string const &key) const; |
44 | 55 | |
49 | 60 | // replaces the DEFINE's in text |
50 | 61 | void replaceDefines(std::string &text); |
51 | 62 | void insert(LinearMap &linMap, std::string const &line); |
63 | ||
64 | void fixRelativeLocations(); | |
52 | 65 | }; |
53 | 66 | |
54 | 67 | inline size_t PolicyFile::size() const |
1 | 1 | |
2 | 2 | #include <bobcat/pattern> |
3 | 3 | #include <bobcat/mstream> |
4 | ||
4 | #include <bobcat/argconfig> | |
5 | #include <bobcat/tempstream> | |
6 | #include <bobcat/user> | |
7 | ||
5 | 8 | #include "../util/util.h" |
9 | #include "../msg/msg.h" | |
6 | 10 | #include "../options/options.h" |
7 | #include "../msg/msg.h" | |
8 | 11 | |
9 | 12 | using namespace std; |
10 | 13 | using namespace FBB; |
0 | 0 | #include "policyfile.ih" |
1 | 1 | |
2 | PolicyFile::PolicyFile(string const &policyPath) | |
2 | PolicyFile::PolicyFile(Options &options) | |
3 | 3 | : |
4 | d_policyPath(policyPath) | |
4 | d_options(options) | |
5 | 5 | { |
6 | reload(); | |
6 | load(); | |
7 | 7 | } |
8 | 8 | |
9 | 9 |
0 | #include "policyfile.ih" | |
1 | ||
2 | void PolicyFile::reload() | |
3 | { | |
4 | d_configfile.open(d_policyPath); | |
5 | ||
6 | d_use = LinearMap( | |
7 | &s_defaultKeyword[0], &s_defaultKeyword[s_nDefaultKeywords] | |
8 | ); | |
9 | ||
10 | d_define.clear(); | |
11 | d_command.clear(); | |
12 | ||
13 | fetchCommands(); | |
14 | ||
15 | string &base = d_use["BASE"]; | |
16 | ||
17 | base += "/."; // the . is required by mkdir | |
18 | ||
19 | char const *cp = base.c_str(); | |
20 | ||
21 | if (!Util::mkdir(cp) || chdir(cp)) | |
22 | fmsg << "Can't chdir to `" << cp << '\'' << endl; | |
23 | ||
24 | base.resize(base.length() - 1); // cut off the . again | |
25 | ||
26 | m2 << "(re)loaded the policy file `" << d_policyPath << '\'' << endl; | |
27 | } | |
28 | ||
29 | ||
30 | ||
31 | ||
32 | ||
33 | ||
34 |
0 | /* | |
1 | demo.cc | |
2 | ||
3 | g++ demo.cc -L../.. -lstealth | & less | |
4 | */ | |
5 | ||
6 | #include "demo.h" | |
7 | ||
8 | int main(int argc, char **argv, char **envp) | |
9 | { | |
10 | try | |
11 | { | |
12 | Reporter rep("report"); | |
13 | ||
14 | rep << Util::date << ": Hello world\n"; | |
15 | ||
16 | rep.reset(); | |
17 | ||
18 | string s; | |
19 | ||
20 | cout << "========= 0 ===========\n"; | |
21 | ||
22 | while (getline(rep, s)) | |
23 | cout << "Added: " << s << "\n"; | |
24 | ||
25 | cout << "========= 1 ===========\n"; | |
26 | ||
27 | sleep(5); | |
28 | ||
29 | rep.reinit(); // make sure we can add new info | |
30 | // as a new run | |
31 | ||
32 | // insert info | |
33 | rep << Util::date << ": Hello world (2nd time)\n"; | |
34 | ||
35 | rep.reset(); // reset the stream to read it again | |
36 | ||
37 | while (getline(rep, s)) | |
38 | cout << "Added: " << s << "\n"; | |
39 | ||
40 | cout << "========= 2 ===========\n"; | |
41 | ||
42 | return 0; | |
43 | } | |
44 | catch(exception const &e) | |
45 | { | |
46 | cerr << "Exception " << e.what() << "\n"; | |
47 | return 1; | |
48 | } | |
49 | } |
0 | #include <iostream> | |
1 | #include <string> | |
2 | ||
3 | #include "../stealthreport.h" | |
4 | #include "../../util/util.h" | |
5 | ||
6 | using namespace std; |
0 | #include "report.ih" | |
1 | ||
2 | void Report::mail() | |
3 | { | |
4 | if (hasMail()) | |
5 | processMail(); | |
6 | else | |
7 | m3 << "No new logs to mail" << endl; | |
8 | } |
0 | #include "report.ih" | |
1 | ||
2 | void Report::processMail() | |
3 | { | |
4 | if (d_options.logMail()) | |
5 | { | |
6 | rewind(); | |
7 | ||
8 | string line; | |
9 | while (std::getline(*this, line)) | |
10 | imsg << "Mail: " << line << endl; | |
11 | } | |
12 | ||
13 | if (d_options.sendMail()) | |
14 | sendMail(); | |
15 | ||
16 | refresh(); | |
17 | } |
0 | #include "report.ih" | |
1 | ||
2 | void Report::refresh() | |
3 | { | |
4 | clear(); | |
5 | ||
6 | d_startSize = endpos(); | |
7 | ||
8 | d_beginMail = d_startSize; | |
9 | } | |
10 | ||
11 | ||
12 | ||
13 | ||
14 | ||
15 | ||
16 |
0 | #ifndef REPORT_H_ | |
1 | #define REPORT_H_ | |
2 | ||
3 | #include <string> | |
4 | #include <fstream> | |
5 | ||
6 | class Options; | |
7 | class PolicyFile; | |
8 | ||
9 | class Report: public std::fstream | |
10 | { | |
11 | std::string d_name; | |
12 | ||
13 | Options &d_options; | |
14 | PolicyFile const &d_policyFile; | |
15 | ||
16 | std::ios::pos_type d_startSize; | |
17 | std::ios::pos_type d_beginMail; | |
18 | ||
19 | std::string d_headerLine; | |
20 | ||
21 | public: | |
22 | Report(Options &options, PolicyFile const &policyFile); | |
23 | ~Report(); | |
24 | ||
25 | Report(Report const &other) = delete; | |
26 | Report &operator=(Report const &other) = delete; | |
27 | ||
28 | void timestamp(char const *label, size_t nScans); | |
29 | void mail(); | |
30 | void scanHeader(); // writes the integrity scan header, | |
31 | // initializes d_beginMail | |
32 | private: | |
33 | void rewind(); // prepare for reading | |
34 | void processMail(); | |
35 | void sendMail(); | |
36 | void refresh(); // set d_beginMail to the log's EOF pos. | |
37 | bool hasMail(); // true if there is info beyond | |
38 | // d_beginMail | |
39 | ||
40 | std::ios::pos_type endpos(); | |
41 | }; | |
42 | ||
43 | #endif | |
44 |
0 | #include "report.h" | |
1 | ||
2 | #include <iostream> | |
3 | #include <sstream> | |
4 | ||
5 | #include <bobcat/exception> | |
6 | #include <bobcat/mstream> | |
7 | #include <bobcat/process> | |
8 | ||
9 | #include "../options/options.h" | |
10 | #include "../msg/msg.h" | |
11 | #include "../policyfile/policyfile.h" | |
12 | ||
13 | namespace Icmbuild | |
14 | { | |
15 | extern char const version[]; | |
16 | } | |
17 | ||
18 | using namespace FBB; | |
19 | using namespace std; | |
20 | ||
21 | inline ios::pos_type Report::endpos() | |
22 | { | |
23 | return seekp(0, ios::end).tellp(); | |
24 | } |
0 | #include "report.ih" | |
1 | ||
2 | Report::Report(Options &options, PolicyFile const &policyFile) | |
3 | : | |
4 | fstream(policyFile["REPORT"], ios::out | ios::ate | ios::in), | |
5 | d_name(policyFile["REPORT"]), | |
6 | d_options(options), | |
7 | d_policyFile(policyFile) | |
8 | { | |
9 | if (not good()) | |
10 | { | |
11 | clear(); | |
12 | open(d_name, ios::out | ios::in | ios::trunc); | |
13 | } | |
14 | ||
15 | if (not good()) | |
16 | fmsg << "cannot write report file `" << d_name << '\'' << noidl; | |
17 | ||
18 | ostringstream headerTxt; | |
19 | headerTxt << "\n" | |
20 | "STEALTH (" << Icmbuild::version << ") started at " << | |
21 | d_options.rfc2822() << '\n'; | |
22 | ||
23 | d_headerLine = headerTxt.str(); | |
24 | ||
25 | *this << d_headerLine << endl; | |
26 | ||
27 | refresh(); | |
28 | } | |
29 | ||
30 | ||
31 | ||
32 | ||
33 |
0 | #include "report.ih" | |
1 | ||
2 | void Report::scanHeader() | |
3 | { | |
4 | d_startSize = endpos(); | |
5 | ||
6 | *this << "STEALTH integrity scan at " << d_options.rfc2822() << endl; | |
7 | ||
8 | d_beginMail = tellp(); | |
9 | } | |
10 | ||
11 | ||
12 | ||
13 | ||
14 | ||
15 | ||
16 |
0 | #include "report.ih" | |
1 | ||
2 | void Report::sendMail() | |
3 | { | |
4 | m3 << "Mailing new logs using: " << | |
5 | d_policyFile["MAILER"] << ' ' << | |
6 | d_policyFile["MAILARGS"] << " " << | |
7 | d_policyFile["EMAIL"] << endl; | |
8 | ||
9 | // mailcommand subject and email are called as separate arguments | |
10 | // If subject contains blanks, they will be interpreted as separate | |
11 | // arguments by the `mail' IOFork. Usually d_policyFile["MAILER"] will | |
12 | // call a script. | |
13 | ||
14 | Process mail( | |
15 | Process::CIN | Process::IGNORE_COUT | Process::IGNORE_CERR, | |
16 | d_policyFile["MAILER"] + ' ' + | |
17 | d_policyFile["MAILARGS"] + ' ' + | |
18 | d_policyFile["EMAIL"] | |
19 | ); | |
20 | ||
21 | mail.start(); | |
22 | ||
23 | mail << d_headerLine << '\n'; | |
24 | ||
25 | rewind(); | |
26 | ||
27 | string line; | |
28 | while (std::getline(*this, line)) | |
29 | mail << line << '\n'; | |
30 | ||
31 | mail.close(); | |
32 | mail.waitForChild(); | |
33 | } |
0 | #include "report.ih" | |
1 | ||
2 | void Report::timestamp(char const *label, size_t nScans) | |
3 | { | |
4 | static char plural[] = "s"; | |
5 | ||
6 | plural[0] = nScans != 1 ? 's' : 0; | |
7 | ||
8 | *this << "STEALTH " << label << " after " << nScans << " scan" << | |
9 | plural << " at " << d_options.rfc2822() << endl; | |
10 | mail(); | |
11 | } |
0 | This file lists non-standard software only. Thus, standard utilities like cp, | |
1 | mv, sed, etc, etc, are not explicitly mentioned. Neither is the gcc compiler | |
2 | explicitly mentioned, but a fairly recent one is assumed. | |
3 | ||
4 | Required software for building Stealth 4.00.00 | |
5 | ---------------------------------------------- | |
6 | ||
7 | libbobcat-dev (>= 3.25.01), | |
8 | ||
9 | ||
10 | To use the provided build-script: | |
11 | ||
12 | icmake (>= 7.22.00) | |
13 | ||
14 | To construct the manual and map-page: | |
15 | ||
16 | yodl (>= 3.05.0) | |
17 | ||
18 | To construct the manual: | |
19 | ||
20 | texlive-latex-base, | |
21 | texlive-generic-recommended, | |
22 | texlive-latex-recommended, | |
23 | texlive-fonts-recommended, | |
24 | cm-super-minimal, | |
25 | ghostscript | |
26 | ||
27 |
0 | 0 | #include "runmode.ih" |
1 | 1 | |
2 | LinearMap<volatile RunMode::Mode, char const *> const RunMode::s_modeName = | |
2 | LinearMap<RunMode::Mode, char const *> const RunMode::s_modeName = | |
3 | 3 | { |
4 | 4 | {INTEGRITY_SCAN, "INTEGRITY_SCAN"}, |
5 | {WAIT, "WAIT"}, | |
6 | 5 | {RERUN, "RERUN"}, |
7 | 6 | {SUSPEND, "SUSPEND"}, |
8 | 7 | {RESUME, "RESUME"}, |
9 | 8 | {RELOAD, "RELOAD"}, |
10 | 9 | {TERMINATE, "TERMINATE"}, |
11 | 10 | }; |
12 | ||
13 | LinearMap<volatile RunMode::Mode, int> const RunMode::s_mode2signal = | |
14 | { | |
15 | {RERUN, SIGHUP}, | |
16 | {RELOAD, SIGPIPE}, | |
17 | {RESUME, SIGUSR2}, | |
18 | {SUSPEND, SIGUSR1}, | |
19 | {TERMINATE, SIGTERM}, | |
20 | }; | |
21 | 11 | |
22 | 12 | |
23 | 13 |
0 | 0 | #ifndef INCLUDED_RUNMODE_ |
1 | 1 | #define INCLUDED_RUNMODE_ |
2 | 2 | |
3 | #include <iostream> | |
3 | 4 | #include <bobcat/linearmap> |
4 | 5 | |
5 | 6 | #include "../stealthenums/stealthenums.h" |
6 | 7 | |
7 | 8 | struct RunMode: public StealthEnums |
8 | 9 | { |
10 | friend std::ostream &operator<<(std::ostream &out, RunMode const &mode); | |
11 | ||
9 | 12 | private: |
10 | static FBB::LinearMap<volatile Mode, char const *> const s_modeName; | |
11 | static FBB::LinearMap<volatile Mode, int> const s_mode2signal; | |
13 | static FBB::LinearMap<Mode, char const *> const s_modeName; | |
12 | 14 | |
13 | 15 | volatile Mode d_mode = INTEGRITY_SCAN; |
14 | 16 | |
15 | 17 | public: |
16 | bool mode(Mode query) const; | |
18 | bool hasMode(Mode query) const; | |
17 | 19 | Mode mode() const; |
18 | char const *modeName() const; | |
19 | 20 | |
20 | 21 | void setMode(Mode mode); |
21 | bool interrupted() const; // a running integrity scan was interrupted | |
22 | ||
23 | static Mode validate(int mode); | |
22 | 24 | }; |
23 | 25 | |
24 | inline char const *RunMode::modeName() const | |
26 | inline RunMode::Mode RunMode::validate(int mode) | |
25 | 27 | { |
26 | return s_modeName.find(d_mode)->second; | |
28 | return | |
29 | ((mode - 1) & mode) == 0 | |
30 | && | |
31 | mode <= UNKNOWN ? | |
32 | static_cast<Mode>(mode) | |
33 | : | |
34 | UNKNOWN; | |
27 | 35 | } |
28 | 36 | |
29 | 37 | inline RunMode::Mode RunMode::mode() const |
31 | 39 | return d_mode; |
32 | 40 | } |
33 | 41 | |
34 | inline bool RunMode::mode(Mode mode) const | |
42 | inline bool RunMode::hasMode(Mode mode) const | |
35 | 43 | { |
36 | 44 | return d_mode & mode; |
37 | 45 | } |
38 | ||
39 | inline bool RunMode::interrupted() const | |
46 | ||
47 | inline std::ostream &operator<<(std::ostream &out, RunMode const &mode) | |
40 | 48 | { |
41 | return mode(SUSPEND | TERMINATE | RELOAD); | |
49 | return out << RunMode::s_modeName.find(mode.mode())->second; | |
42 | 50 | } |
43 | 51 | |
44 | 52 | #endif |
0 | 0 | #include "runmode.h" |
1 | ||
2 | #include <unistd.h> | |
3 | #include <csignal> | |
4 | ||
5 | //#include "../lock/lock.h" | |
6 | #include "../options/options.h" | |
7 | 1 | |
8 | 2 | using namespace std; |
9 | 3 | using namespace FBB; |
1 | 1 | |
2 | 2 | void RunMode::setMode(Mode mode) |
3 | 3 | { |
4 | if ((d_mode = mode) == LEAVE) | |
5 | unlink(Options::instance().runFile().c_str()); | |
4 | d_mode = mode; | |
6 | 5 | } |
7 | 6 |
0 | /var/stealth/target/report { | |
0 | /root/stealth/report /var/log/stealth/client-small.log { | |
1 | 1 | weekly |
2 | 2 | rotate 12 |
3 | 3 | compress |
4 | 4 | missingok |
5 | copytruncate | |
6 | sharedscripts | |
5 | 7 | prerotate |
6 | /usr/bin/stealth --suppress /var/run/stealth.target | |
8 | /usr/bin/stealth --suspend /root/stealth/small.uds | |
7 | 9 | endscript |
8 | postrotate | |
9 | /usr/bin/stealth --resume /var/run/stealth.target | |
10 | postrotate | |
11 | /usr/bin/stealth --resume /root/stealth/small.uds | |
10 | 12 | endscript |
11 | 13 | } |
29 | 29 | (*) |
30 | 30 | echo " |
31 | 31 | $PROG by Frank B. Brokken (f.b.brokken@rug.nl) |
32 | Usage: $PROG pidfile configfile [skipfile] | |
32 | Usage: $PROG uds policyfile [skipfile] | |
33 | 33 | where: |
34 | pidfile: absolute path to pidfile to be used by ${STEALTH} | |
35 | configfile: absolute path to configuration file to be used by ${STEALTH} | |
36 | skipfile: absolute path to file holding files to skip (optional) | |
34 | uds: absolute path to the Unix Domain Socket to be used | |
35 | policyfile: absolute path to the policyfile to be used | |
36 | skipfile: absolute path to the skipfile to be used (optional) | |
37 | 37 | |
38 | calls $STEALTH} --rerun pidfile. | |
38 | calls $STEALTH} --rerun uds. | |
39 | 39 | If that fails, |
40 | ${STEALTH} --daemon pidfile -q configfile | |
40 | ${STEALTH} --daemon uds policyfile | |
41 | 41 | or (if skipfile was specified) |
42 | ${STEALTH} --daemon pidfile -s skipfile -q configfile | |
42 | ${STEALTH} --daemon uds policyfile -s skipfile policyfile | |
43 | 43 | is started. |
44 | 44 | " |
45 | 45 | exit 1 |
1 | 1 | |
2 | 2 | grep 'STEALTH\|MODIFIED\|ADDED\|REMOVED\|SKIPPING' | sort | uniq | |
3 | 3 | /usr/bin/mail -s "$2" $3 |
4 | ||
5 | ||
6 | # echo "$0 started with arguments: | |
7 | # =============================================" > /tmp/stealth.mail | |
8 | # | |
9 | # while [ "$1" != "" ] | |
10 | # do | |
11 | # echo "$1" >> /tmp/stealth.mail | |
12 | # shift | |
13 | # done | |
14 | # | |
15 | # echo "== contents begin ===========================" >> /tmp/stealth.mail | |
16 | # | |
17 | # cat >> /tmp/stealth.mail | |
18 | # | |
19 | # echo "== contents end =============================" >> /tmp/stealth.mail |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::acceptMode(Mode mode) | |
2 | string Stealth::acceptMode(Mode mode) | |
3 | 3 | { |
4 | d_run.setMode(mode); | |
5 | d_ipc.sendRequestor("OK"); | |
4 | d_task.setMode(mode); | |
5 | return ""; | |
6 | 6 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | // automatically switch to an integrity scan after reload, rerun and resume. | |
3 | ||
4 | void Stealth::autoScan(char const *label) | |
5 | { | |
6 | m2 << "automatically starting an INTEGRITY_SCAN following --" << label | |
7 | << endl; | |
8 | d_task.setMode(INTEGRITY_SCAN); | |
9 | d_autoJob = true; | |
10 | d_job.notify(); | |
11 | } |
1 | 1 | |
2 | 2 | void Stealth::childProcess() |
3 | 3 | { |
4 | // prepareDaemon("/tmp/serr", "/tmp/serr"); // by Fork. | |
4 | 5 | prepareDaemon(); // by Fork. |
5 | 6 | |
6 | doChores(); | |
7 | // start the ipc interface thread | |
8 | thread(startThread, &Stealth::ipcInterface, this).detach(); | |
9 | ||
10 | doTasks(); | |
7 | 11 | |
8 | 12 | m1 << d_options.basename() << " (process " << getpid() << |
9 | 13 | ") terminates" << endl; |
0 | #include "stealth.ih" | |
1 | ||
2 | bool Stealth::contactPeer() | |
3 | { | |
4 | if (not d_options.ipc()) | |
5 | return false; | |
6 | ||
7 | Signal &signal = Signal::instance(); | |
8 | signal.add(SIGUSR1, *this); | |
9 | ||
10 | if (d_ipc.signalDaemon()) | |
11 | { | |
12 | d_ipc.timedWait(s_contactPeerWaitSeconds); | |
13 | ||
14 | if (d_ipc.timeout()) | |
15 | cout << "No reply from daemon (pid " << d_ipc.daemonPid() << | |
16 | ')' << endl; | |
17 | else if (d_ipc.requestText() != "OK") | |
18 | cout << d_ipc.requestText() << endl; | |
19 | ||
20 | return true; | |
21 | } | |
22 | ||
23 | return false; | |
24 | } | |
25 | ||
26 | ||
27 |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | FBB::LinearMap<Stealth::Mode, Stealth::Action> Stealth::s_task = | |
2 | FBB::LinearMap<Stealth::Mode, Stealth::Task> Stealth::s_task = | |
3 | 3 | { |
4 | {RELOAD, &Stealth::reload}, | |
5 | {TERMINATE, &Stealth::terminate}, | |
4 | {RELOAD, &Stealth::reload}, // autoscan | |
5 | {TERMINATE, &Stealth::terminate}, // terminates | |
6 | 6 | {INTEGRITY_SCAN, &Stealth::integrityScan}, |
7 | 7 | {SUSPEND, &Stealth::suspend}, |
8 | {RESUME, &Stealth::resume}, | |
8 | {RESUME, &Stealth::resume}, // autoscan | |
9 | {RERUN, &Stealth::rerun}, // autoscan | |
9 | 10 | }; |
10 | 11 | |
12 | // possible incoming requests at the ipcInterface | |
11 | 13 | FBB::LinearMap<Stealth::Mode, Stealth::Action> Stealth::s_request = |
12 | 14 | { |
15 | {INTEGRITY_SCAN, &Stealth::unknownRequest}, | |
16 | ||
17 | {RERUN, &Stealth::rerunRequest}, | |
18 | {SUSPEND, &Stealth::suspendRequest}, | |
19 | {RESUME, &Stealth::resumeRequest}, | |
13 | 20 | {RELOAD, &Stealth::reloadRequest}, |
14 | {RERUN, &Stealth::rerunRequest}, | |
15 | {RESUME, &Stealth::resumeRequest}, | |
16 | {SUSPEND, &Stealth::suspendRequest}, | |
17 | 21 | {TERMINATE, &Stealth::terminateRequest}, |
22 | ||
18 | 23 | {UNKNOWN, &Stealth::unknownRequest}, |
19 | 24 | }; |
20 | 25 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::defineSupportedSignals() | |
3 | { | |
4 | Signal &signal = Signal::instance(); | |
5 | ||
6 | signal.add(SIGTERM, *this); // ends the running Stealth program. | |
7 | signal.add(SIGINT, *this); | |
8 | ||
9 | signal.add(SIGUSR1, *this); | |
10 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::deniedMode(char const *request) | |
2 | std::string Stealth::deniedMode(char const *request) | |
3 | 3 | { |
4 | 4 | ostringstream ostr; |
5 | 5 | |
6 | ostr << "Stealth deamon " << getpid() << " in mode " << | |
7 | d_run.modeName() << " cannot do " << request; | |
6 | ostr << "Stealth deamon (pid = " << getpid() << "): `" << request << | |
7 | "' not available in mode " << d_task; | |
8 | 8 | |
9 | 9 | |
10 | d_ipc.sendRequestor(ostr.str()); | |
10 | m2 << "ignored --rerun in mode " << d_task << endl; | |
11 | 11 | |
12 | m2 << "ignored --rerun in mode " << d_run.modeName() << endl; | |
12 | return ostr.str(); | |
13 | 13 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | 2 | Stealth::~Stealth() |
3 | {} | |
3 | { | |
4 | if (d_options.daemon()) | |
5 | unlink(d_options.unixDomainSocket().c_str()); | |
6 | ||
7 | delete d_logReportbuf; | |
8 | } | |
4 | 9 | |
5 | 10 | |
6 | 11 |
0 | #include "stealth.ih" | |
1 | ||
2 | // called by processPolicy and childProcess | |
3 | ||
4 | void Stealth::doChores() | |
5 | { | |
6 | policyDepDataMembers(); | |
7 | ||
8 | defineSupportedSignals(); | |
9 | ||
10 | if (d_options.dryrun()) | |
11 | d_stealthLog << "--dry-run: SH/SSH connections not established" << | |
12 | endl; | |
13 | else | |
14 | d_integrityScanner->startCommandShells(); | |
15 | ||
16 | processRequests(); // Stealth terminates once this function | |
17 | // ends | |
18 | } | |
19 | ||
20 | ||
21 | ||
22 | ||
23 | ||
24 | ||
25 | ||
26 | ||
27 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::doTasks() | |
3 | { | |
4 | if (not d_options.ipc()) | |
5 | { | |
6 | m1 << "timestamps use " << | |
7 | (d_options.timestamp() == TIMESTAMPS ? | |
8 | "local time" | |
9 | : | |
10 | "UTC" | |
11 | ) << endl; | |
12 | } | |
13 | ||
14 | d_policyFile->chdirBase(); | |
15 | ||
16 | if (d_options.dryrun()) | |
17 | *d_report << "--dry-run: SH/SSH connections not established" << endl; | |
18 | else | |
19 | d_integrityScanner->startCommandShells(); | |
20 | ||
21 | jobsHandler(); | |
22 | } | |
23 | ||
24 | ||
25 | ||
26 | ||
27 | ||
28 | ||
29 | ||
30 | ||
31 |
0 | #include "stealth.ih" | |
1 | ||
2 | bool Stealth::incomingRequest(istream &in, ostream &out) | |
3 | { | |
4 | int request; // read te request | |
5 | if (not (in >> request).ignore(numeric_limits<int>::max(), '\n')) | |
6 | request = UNKNOWN; | |
7 | ||
8 | RunMode incoming; | |
9 | incoming.setMode(RunMode::validate(request)); | |
10 | ||
11 | string answer = (this->*s_request.find(incoming.mode())->second)(); | |
12 | ||
13 | if (not answer.empty()) // error or no operation (nop) | |
14 | { | |
15 | if (answer == "nop") | |
16 | answer.clear(); | |
17 | ||
18 | out << answer << endl; | |
19 | return false; // no-action or error request: | |
20 | // read the next request | |
21 | } | |
22 | ||
23 | d_pending = incoming; | |
24 | return true; | |
25 | } |
1 | 1 | |
2 | 2 | void Stealth::integrityScan() |
3 | 3 | { |
4 | d_stealthLog.scanHeader(); | |
4 | d_report->scanHeader(); | |
5 | 5 | |
6 | 6 | if (d_options.dryrun()) |
7 | d_stealthLog << "--dry-run: integrity scan suppressed" << endl; | |
8 | else | |
9 | d_integrityScanner->run(); | |
7 | { | |
8 | *d_report << "--dry-run: would have performed an integrity scan" << | |
9 | endl; | |
10 | return; | |
11 | } | |
10 | 12 | |
11 | if (d_run.interrupted()) | |
12 | return; | |
13 | ||
14 | d_run.setMode(d_options.daemon() or d_options.repeat() ? WAIT : LEAVE); | |
13 | d_integrityScanner->run(); | |
14 | m2 << "Integrity scan completed" << endl; | |
15 | 15 | } |
16 | 16 | |
17 | 17 |
0 | #include "stealth.ih" | |
1 | ||
2 | // see also documentation/images/ipcinterface.jpg | |
3 | ||
4 | void Stealth::ipcInterface() | |
5 | try | |
6 | { | |
7 | string const &udsName = d_options.unixDomainSocket(); | |
8 | ||
9 | m2 << "Unix Domain Socket: " << udsName << endl; | |
10 | ||
11 | LocalServerSocket uds(udsName); | |
12 | ||
13 | uds.listen(); | |
14 | ||
15 | do | |
16 | { | |
17 | int socket = uds.accept(); // accept a request | |
18 | ||
19 | IFdStream in(socket); // stream to read the request from | |
20 | OFdStream out(socket); // stream to write answers to the | |
21 | // ipc-stealth process to. | |
22 | if (incomingRequest(in, out)) | |
23 | { | |
24 | d_ipc.wait(); // wait until an IPC command can be | |
25 | // accepted | |
26 | ||
27 | out << endl; // all commands succeed: empty return | |
28 | // texts indicates so. | |
29 | notifyTask(); | |
30 | } | |
31 | } | |
32 | while (not d_task.hasMode(TERMINATE)); | |
33 | } | |
34 | catch (exception const &exc) | |
35 | { | |
36 | ostringstream msg; | |
37 | msg << '\n' << exc.what() << "\n" | |
38 | " TERMINATING: exception in ipcInterface:\n"; | |
39 | ||
40 | imsg << msg.str() << endl; | |
41 | *d_report << msg.str() << endl; | |
42 | d_report->mail(); | |
43 | ||
44 | d_pending.setMode(TERMINATE); | |
45 | d_ipc.wait(); | |
46 | notifyTask(); | |
47 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | bool Stealth::ipcMode() | |
3 | { | |
4 | if (not d_options.ipc()) | |
5 | return false; | |
6 | ||
7 | int fd; | |
8 | LocalClientSocket uds; | |
9 | ||
10 | try | |
11 | { | |
12 | uds.open(d_options.unixDomainSocket()); | |
13 | fd = uds.connect(); | |
14 | } | |
15 | catch (...) | |
16 | { | |
17 | throw Exception() << "can't connect to `" << | |
18 | d_options.unixDomainSocket() << '\''; | |
19 | } | |
20 | ||
21 | OFdStream out(fd); | |
22 | out << d_options.mode() << endl; // send the requested mode | |
23 | ||
24 | IFdStream in(fd); | |
25 | string answer; // wait for the answer | |
26 | getline(in, answer); | |
27 | ||
28 | if (not answer.empty()) // show the answer if something | |
29 | throw Exception() << answer; // went wrong. | |
30 | ||
31 | return true; | |
32 | } | |
33 | ||
34 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::jobsHandler() | |
3 | { | |
4 | bool prompt = not d_options.daemon() && d_options.repeat(); | |
5 | bool runOnce = not d_options.daemon() && not d_options.repeat(); | |
6 | ||
7 | if (prompt) | |
8 | { | |
9 | thread(startThread, &Stealth::waitForKey, this).detach(); | |
10 | cout << "? " << flush; | |
11 | } | |
12 | ||
13 | while (true) | |
14 | { | |
15 | nextJob(); | |
16 | ||
17 | m1 << d_task << " next." << endl; | |
18 | ||
19 | // process the current request | |
20 | (this->*(s_task.find(d_task.mode())->second))(); | |
21 | ||
22 | d_report->mail(); | |
23 | ||
24 | if (runOnce) | |
25 | break; | |
26 | ||
27 | if (d_task.hasMode(TERMINATE)) | |
28 | { | |
29 | d_ipc.notify(); | |
30 | break; | |
31 | } | |
32 | ||
33 | if (d_autoJob) | |
34 | { | |
35 | d_autoJob = false; | |
36 | continue; | |
37 | } | |
38 | d_ipc.notify(); | |
39 | } | |
40 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::logMsg(char const *label) | |
3 | { | |
4 | d_stealthLog << "STEALTH " << label << " after " << | |
5 | d_integrityScanner->nScans() << " scans at " << | |
6 | d_options.rfc2822() << endl; | |
7 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | // Called from performTask() | |
3 | ||
4 | void Stealth::mailLogs() | |
5 | { | |
6 | if (not d_stealthLog.hasMail()) | |
7 | { | |
8 | m3 << "No new logs to mail" << endl; | |
9 | return; | |
10 | } | |
11 | ||
12 | processMail(); | |
13 | } | |
14 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::nextJob() | |
3 | { | |
4 | if (not d_options.repeat()) // if the scan is not automatically | |
5 | d_job.wait(); // restarted, then wait for the next job | |
6 | else | |
7 | { | |
8 | size_t nSeconds = d_options.nextIntegrityScan(); | |
9 | ||
10 | m2 << "waiting for " << nSeconds << " seconds or for a command" << | |
11 | endl; | |
12 | ||
13 | while (true) | |
14 | { | |
15 | auto cvStatus = d_job.wait_for(chrono::seconds(nSeconds)); | |
16 | ||
17 | m2 << "wait ends" << endl; | |
18 | ||
19 | if (cvStatus != cv_status::timeout) | |
20 | break; | |
21 | ||
22 | m2 << "timeout" << endl; | |
23 | ||
24 | if | |
25 | ( | |
26 | d_task.hasMode(SUSPEND) // At timeout during | |
27 | || // suspend, or | |
28 | d_integrityScanner->active() // still busy scanning | |
29 | ) | |
30 | { | |
31 | m2 << "SUSPEND or actively scanning: wait some more" << endl; | |
32 | continue; // then wait some more | |
33 | } | |
34 | ||
35 | d_task.setMode(INTEGRITY_SCAN); | |
36 | d_autoJob = true; | |
37 | break; | |
38 | } | |
39 | } | |
40 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::notifyTask() | |
3 | { | |
4 | d_task = d_pending; // set the next request | |
5 | d_pending.setMode(UNKNOWN); // clear the pending request | |
6 | ||
7 | d_job.notify(); // notify processRequests (i.e., | |
8 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | int LogReportbuf::overflow(int ch) | |
3 | { | |
4 | if (ch != EOF) | |
5 | d_report.put(ch); | |
6 | return ch; | |
7 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | 2 | void Stealth::parentProcess() |
3 | { | |
4 | d_ipc.writeRunFile(pid()); | |
5 | } | |
3 | {} | |
6 | 4 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::policyDepDataMembers() | |
3 | { | |
4 | d_policyFile = make_shared<PolicyFile>(d_options.policyFilePath()); | |
5 | ||
6 | d_stealthLog.open((*d_policyFile)["REPORT"]); | |
7 | ||
8 | d_integrityScanner = make_shared<IntegrityScanner>( | |
9 | d_run, *d_policyFile, d_stealthLog | |
10 | ); | |
11 | } | |
12 | ||
13 |
0 | #include "stealth.ih" | |
1 | ||
2 | // Called by main() once all preliminary actions have been completed. | |
3 | ||
4 | void Stealth::policyMode() | |
5 | { | |
6 | d_logUnit.setupLogs(); | |
7 | setUniquePtrs(); | |
8 | ||
9 | if (d_options.daemon()) | |
10 | fork(); // creates the daemon. Its childProcess | |
11 | else // does the tasks. | |
12 | doTasks(); | |
13 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::process(Mode request) | |
3 | try | |
4 | { | |
5 | (this->*(s_task.find(request)->second))(); | |
6 | } | |
7 | catch (Mode) | |
8 | { | |
9 | terminate(); | |
10 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::processMail() | |
3 | { | |
4 | if (d_options.logMail()) | |
5 | { | |
6 | d_stealthLog.rewind(); | |
7 | ||
8 | string line; | |
9 | while (getline(d_stealthLog.in(), line)) | |
10 | imsg << "Mail: " << line << endl; | |
11 | } | |
12 | ||
13 | if (d_options.sendMail()) | |
14 | sendMail(); | |
15 | } | |
16 | ||
17 | ||
18 | ||
19 | ||
20 |
0 | #include "stealth.ih" | |
1 | ||
2 | // Called by main() once all preliminary actions have been completed. | |
3 | ||
4 | // Signals are sent by sendSignal. Signals are caught by handleProcessSignals | |
5 | // contactOtherStealth sends the signals depending on command-line options | |
6 | ||
7 | void Stealth::processPolicy() | |
8 | { | |
9 | if (d_options.daemon()) | |
10 | fork(); // creates the daemon. Its childProcess | |
11 | else // does the chores. | |
12 | doChores(); | |
13 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | // requests are received through interrupts (SIGUSR1, SIGTERM, SIGINT). For | |
3 | // SIGUSR1 requests the type of request is written in line 2 of the run file. | |
4 | // When a SIGUSR1 signal is received, the request | |
5 | ||
6 | void Stealth::processRequests() | |
7 | { | |
8 | while (true) | |
9 | { | |
10 | Mode request = d_run.mode(); | |
11 | ||
12 | if (request == LEAVE) | |
13 | break; | |
14 | ||
15 | m1 << "MODE: " << d_run.modeName() << endl; | |
16 | ||
17 | d_stealthLog.refresh(); | |
18 | ||
19 | process(request); // process the current request | |
20 | ||
21 | mailLogs(); | |
22 | ||
23 | waitForRequest(); | |
24 | } | |
25 | } |
1 | 1 | |
2 | 2 | void Stealth::reload() |
3 | 3 | { |
4 | logMsg("reloads its policy file"); | |
5 | ||
6 | mailLogs(); | |
7 | ||
8 | d_stealthLog.close(); | |
4 | timestamp("reloads its policy file"); | |
9 | 5 | |
10 | 6 | if (d_options.dryrun()) |
11 | d_stealthLog << "--dry-run: reload suppressed" << endl; | |
7 | *d_report << "--dry-run: would have reloaded the policy file" << endl; | |
12 | 8 | else |
13 | 9 | { |
14 | d_policyFile->reload(); | |
15 | ||
16 | d_stealthLog.open((*d_policyFile)["REPORT"]); | |
17 | ||
18 | d_integrityScanner = make_shared<IntegrityScanner>( | |
19 | d_run, *d_policyFile, d_stealthLog | |
20 | ); | |
10 | PolicyFile *policyFilePtr = new PolicyFile(d_options); | |
11 | ||
12 | Report *reportPtr = new Report(d_options, *policyFilePtr); | |
13 | ||
14 | d_integrityScanner.reset( | |
15 | new IntegrityScanner(d_pending, d_options, | |
16 | *policyFilePtr, *reportPtr) | |
17 | ); | |
21 | 18 | |
22 | 19 | d_integrityScanner->startCommandShells(); |
20 | ||
21 | setupFatalReport(); | |
22 | ||
23 | d_logUnit.setupLogs(d_logReport); | |
24 | ||
25 | d_report.reset(reportPtr); | |
26 | d_policyFile.reset(policyFilePtr); | |
27 | ||
28 | m2 << "reloaded policy file `" << d_options.policyFilePath() << "'\n" | |
29 | "reconstructed the Integrity Scanner" << endl; | |
30 | m3 << "max. download size: " << d_options.maxSizeStr() << endl; | |
23 | 31 | } |
24 | ||
25 | d_run.setMode(INTEGRITY_SCAN); | |
32 | autoScan("reload"); | |
26 | 33 | } |
27 | 34 | |
28 | 35 | |
36 | ||
37 |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::reloadRequest() | |
2 | string Stealth::reloadRequest() | |
3 | 3 | { |
4 | if (d_run.mode(INTEGRITY_SCAN | WAIT | SUSPEND)) | |
5 | acceptMode(RELOAD); | |
6 | else | |
7 | deniedMode("--reload"); | |
4 | string ret = d_task.hasMode(INTEGRITY_SCAN) ? | |
5 | acceptMode(RELOAD) | |
6 | : | |
7 | deniedMode("--reload"); | |
8 | return ret; | |
8 | 9 | } |
9 | 10 | |
10 | 11 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::rerun() | |
3 | { | |
4 | *d_report << "STEALTH explicit integrity scan rerun at " << | |
5 | d_options.rfc2822() << endl; | |
6 | autoScan("rerun"); | |
7 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::rerunRequest() | |
2 | string Stealth::rerunRequest() | |
3 | 3 | { |
4 | if (d_run.mode(WAIT)) | |
5 | acceptMode(INTEGRITY_SCAN); | |
6 | else | |
7 | deniedMode("--rerun"); | |
4 | string ret = d_task.hasMode(INTEGRITY_SCAN) ? | |
5 | acceptMode(RERUN) | |
6 | : | |
7 | deniedMode("--rerun"); | |
8 | ||
9 | return ret; | |
8 | 10 | } |
1 | 1 | |
2 | 2 | void Stealth::resume() |
3 | 3 | { |
4 | d_stealthLog << "STEALTH resumes its tasks at " << d_options.rfc2822() << | |
4 | *d_report << "STEALTH resumes its tasks at " << d_options.rfc2822() << | |
5 | 5 | endl; |
6 | d_run.setMode(INTEGRITY_SCAN); | |
7 | ||
8 | m2 << "resuming tasks: INTEGRITY_SCAN next" << endl; | |
6 | autoScan("resume"); | |
9 | 7 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::resumeRequest() | |
2 | std::string Stealth::resumeRequest() | |
3 | 3 | { |
4 | if (d_run.mode(SUSPEND)) | |
5 | acceptMode(RESUME); | |
6 | else | |
7 | deniedMode("--resume"); | |
4 | string ret = d_task.hasMode(SUSPEND) ? | |
5 | acceptMode(RESUME) | |
6 | : | |
7 | deniedMode("--resume"); | |
8 | ||
9 | return ret; | |
8 | 10 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::sendMail() | |
3 | { | |
4 | d_stealthLog.rewind(); | |
5 | ||
6 | m3 << "Mailing new logs using: " << | |
7 | (*d_policyFile)["MAILER"] << ' ' << | |
8 | (*d_policyFile)["MAILARGS"] << " " << | |
9 | (*d_policyFile)["EMAIL"] << endl; | |
10 | ||
11 | // mailcommand subject and email are called as separate arguments | |
12 | // If subject contains blanks, they will be interpreted as separate | |
13 | // arguments by the `mail' IOFork. Ususally d_policyFile["MAILER"] will | |
14 | // call a script. | |
15 | ||
16 | Process mail( | |
17 | Process::CIN | Process::IGNORE_COUT | Process::IGNORE_CERR, | |
18 | (*d_policyFile)["MAILER"] + ' ' + | |
19 | (*d_policyFile)["MAILARGS"] + ' ' + | |
20 | (*d_policyFile)["EMAIL"] | |
21 | ); | |
22 | ||
23 | mail.start(); | |
24 | ||
25 | mail << d_stealthLog.headerLine() << '\n'; | |
26 | ||
27 | string line; | |
28 | while (getline(d_stealthLog.in(), line)) | |
29 | mail << line << '\n'; | |
30 | ||
31 | mail.close(); | |
32 | mail.waitForChild(); | |
33 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::setUniquePtrs() | |
3 | { | |
4 | d_policyFile.reset(new PolicyFile(d_options)); // the PolicyFile may | |
5 | // redefine some options | |
6 | ||
7 | d_report.reset(new Report(d_options, *d_policyFile)); | |
8 | ||
9 | d_integrityScanner.reset( | |
10 | new IntegrityScanner(d_pending, d_options, *d_policyFile, *d_report) | |
11 | ); | |
12 | ||
13 | setupFatalReport(); | |
14 | ||
15 | d_logUnit.setupLogs(d_logReport); // possibly redefine the log files | |
16 | ||
17 | m2 << "constructed the Integrity Scanner" << endl; | |
18 | m3 << "max. download size: " << d_options.maxSizeStr() << endl; | |
19 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::setupFatalReport() | |
3 | { | |
4 | delete d_logReportbuf; | |
5 | ||
6 | d_logReportbuf = new LogReportbuf(*d_report); | |
7 | d_logReport.rdbuf(d_logReportbuf); | |
8 | d_logReport.clear(); | |
9 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::signalHandler(size_t signal) | |
3 | { | |
4 | d_ipc.signaled(); | |
5 | ||
6 | if (d_options.ipc()) | |
7 | { | |
8 | d_ipc.request(); // retrieve the return message | |
9 | return; | |
10 | } | |
11 | ||
12 | d_request = true; // set to false by unknownRequest. | |
13 | ||
14 | // SIGUSR1 signals are retrieved from | |
15 | // the runfile. Other signals | |
16 | // (TERM, INT) terminate the daemon. | |
17 | (this->*s_request.find( | |
18 | signal == SIGUSR1 ? d_ipc.request() : TERMINATE | |
19 | )->second)(); | |
20 | } | |
21 | ||
22 | ||
23 |
0 | 0 | #ifndef _INCLUDED_STEALTH_H_ |
1 | 1 | #define _INCLUDED_STEALTH_H_ |
2 | 2 | |
3 | #include <iosfwd> | |
3 | 4 | #include <string> |
4 | 5 | #include <memory> |
6 | #include <thread> | |
5 | 7 | |
6 | #include <bobcat/signal> | |
7 | 8 | #include <bobcat/fork> |
9 | #include <bobcat/semaphore> | |
8 | 10 | |
9 | #include "../runmode/runmode.h" // declares LinearMap | |
10 | #include "../ipc/ipc.h" | |
11 | #include "../stealthlog/stealthlog.h" | |
11 | #include "../runmode/runmode.h" // includes LinearMap, StealthEnums | |
12 | #include "../options/options.h" | |
13 | #include "../logunit/logunit.h" | |
12 | 14 | |
13 | 15 | class PolicyFile; |
14 | 16 | class IntegrityScanner; |
15 | class Options; | |
17 | class Report; | |
16 | 18 | |
17 | class Stealth: public StealthEnums, public FBB::Fork, public FBB::SignalHandler | |
19 | class LogReportbuf; | |
20 | ||
21 | class Stealth: public StealthEnums, public FBB::Fork | |
18 | 22 | { |
19 | static size_t const s_contactPeerWaitSeconds = 3; | |
23 | Options d_options; | |
24 | LogUnit d_logUnit; | |
20 | 25 | |
21 | Options &d_options; | |
22 | IPC d_ipc; | |
26 | RunMode d_task; // the current run-mode. | |
27 | RunMode d_pending; // a pending run-mode. | |
23 | 28 | |
24 | RunMode d_run; | |
25 | volatile bool d_request; | |
29 | FBB::Semaphore d_ipc; // Folowing wait Stealth is available | |
30 | // for the next ipc-command | |
26 | 31 | |
27 | StealthLog d_stealthLog; | |
28 | std::shared_ptr<PolicyFile> d_policyFile; | |
29 | std::shared_ptr<IntegrityScanner> d_integrityScanner; | |
32 | FBB::Semaphore d_job; // Semaphore for the next command | |
33 | ||
34 | bool d_autoJob = false; | |
30 | 35 | |
31 | typedef void (Stealth::*Action)(); | |
36 | std::unique_ptr<PolicyFile> d_policyFile; | |
37 | std::unique_ptr<IntegrityScanner> d_integrityScanner; | |
38 | std::unique_ptr<Report> d_report; // and sends mail | |
32 | 39 | |
33 | static FBB::LinearMap<Mode, Action> s_task; | |
40 | std::ostream d_logReport; // configured into LogUnit | |
41 | LogReportbuf *d_logReportbuf = 0; | |
42 | ||
43 | typedef std::string (Stealth::*Action)(); | |
44 | typedef void (Stealth::*Task)(); | |
45 | ||
46 | static FBB::LinearMap<Mode, Task> s_task; | |
34 | 47 | static FBB::LinearMap<Mode, Action> s_request; |
35 | 48 | |
36 | 49 | public: |
37 | 50 | Stealth(); |
38 | 51 | ~Stealth() override; |
39 | 52 | |
40 | bool contactPeer(); // contact a stealth daemon | |
41 | void processPolicy(); // do all policy-file related tasks | |
53 | bool ipcMode(); // contact a stealth daemon | |
54 | void policyMode(); // do all policy-file related tasks | |
42 | 55 | |
43 | 56 | private: |
57 | void parentProcess() override; // no actions here | |
44 | 58 | void childProcess() override; |
45 | void parentProcess() override; | |
46 | void signalHandler(size_t signum) override; | |
47 | void rerunRequest(); | |
48 | void suspendRequest(); | |
49 | void resumeRequest(); | |
50 | void reloadRequest(); | |
51 | void terminateRequest(); | |
52 | void unknownRequest(); | |
53 | void acceptMode(Mode mode); | |
54 | void deniedMode(char const *request); | |
55 | 59 | |
56 | void logMsg(char const *label); | |
60 | std::string rerunRequest(); | |
61 | std::string suspendRequest(); | |
62 | std::string resumeRequest(); | |
63 | std::string reloadRequest(); | |
64 | std::string terminateRequest(); | |
65 | std::string unknownRequest(); | |
66 | std::string acceptMode(Mode mode); | |
67 | std::string deniedMode(char const *request); | |
57 | 68 | |
58 | void mailLogs(); // mail the logs or write them to cout | |
59 | void processMail(); | |
60 | void sendMail(); | |
69 | void doTasks(); // run all scanning (related) tasks | |
70 | void setUniquePtrs(); // initialize the unique_ptrs | |
71 | void setupFatalReport(); // fmsg also inserts into the report and | |
72 | // into the mail | |
61 | 73 | |
62 | void doChores(); // run all scanning (related) tasks | |
63 | void policyDepDataMembers(); | |
64 | void defineSupportedSignals(); | |
74 | void timestamp(char const *label); | |
65 | 75 | |
66 | void processRequests(); | |
67 | void process(Mode request); // process one single request | |
68 | void waitForRequest(); | |
76 | void jobsHandler(); | |
77 | void nextJob(); | |
78 | void reload(); // reload the configuration files. | |
79 | void terminate(); | |
80 | void suspend(); | |
81 | void resume(); | |
82 | void rerun(); | |
83 | void integrityScan(); | |
69 | 84 | |
70 | void integrityScan(); | |
85 | void autoScan(char const *label); | |
71 | 86 | |
87 | void ipcInterface(); // thread | |
88 | bool incomingRequest(std::istream &in, std::ostream &out); | |
89 | void notifyTask(); | |
72 | 90 | |
73 | void reload(); // reload the configuration files. | |
74 | void terminate(); | |
75 | void suspend(); | |
76 | void resume(); | |
91 | void waitForKey(); // thread | |
77 | 92 | |
93 | static void startThread(void (Stealth::*member)(), Stealth *obj); | |
78 | 94 | }; |
79 | 95 | |
80 | 96 | #endif |
81 | ||
82 | ||
83 | ||
84 | ||
85 | ||
86 | ||
87 | ||
88 |
0 | 0 | #include "stealth.h" |
1 | 1 | |
2 | #include <iostream> | |
2 | #include <unistd.h> | |
3 | #include <sstream> | |
4 | #include <thread> | |
5 | #include <chrono> | |
3 | 6 | |
4 | 7 | #include <bobcat/mstream> |
5 | 8 | #include <bobcat/exception> |
6 | 9 | #include <bobcat/linearmap> |
7 | 10 | #include <bobcat/process> |
11 | #include <bobcat/ifdstream> | |
12 | #include <bobcat/ofdstream> | |
13 | #include <bobcat/localclientsocket> | |
14 | #include <bobcat/localserversocket> | |
8 | 15 | |
9 | 16 | #include "../policyfile/policyfile.h" |
10 | 17 | #include "../integrityscanner/integrityscanner.h" |
11 | #include "../options/options.h" | |
18 | #include "../report/report.h" | |
12 | 19 | #include "../msg/msg.h" |
20 | #include "../util/util.h" | |
21 | ||
22 | ||
23 | inline void Stealth::timestamp(char const *label) | |
24 | { | |
25 | d_report->timestamp(label, d_integrityScanner->nScans()); | |
26 | } | |
27 | ||
28 | inline void Stealth::startThread(void (Stealth::*member)(), Stealth *obj) | |
29 | { | |
30 | (obj->*member)(); | |
31 | } | |
13 | 32 | |
14 | 33 | using namespace std; |
15 | 34 | using namespace FBB; |
35 | ||
36 | class LogReportbuf: public streambuf | |
37 | { | |
38 | Report &d_report; | |
39 | ||
40 | public: | |
41 | LogReportbuf(Report &report); | |
42 | ||
43 | private: | |
44 | int overflow(int ch) override; | |
45 | int sync() override; | |
46 | }; |
1 | 1 | |
2 | 2 | Stealth::Stealth() |
3 | 3 | : |
4 | d_options(Options::instance()) // determine all options / runmode | |
4 | d_logUnit(d_options), | |
5 | d_ipc(0), // Semaphores | |
6 | d_job(1), | |
7 | d_logReport(0) | |
5 | 8 | { |
6 | d_run.setMode(d_options.mode()); | |
9 | d_task.setMode(d_options.mode()); | |
10 | d_pending.setMode(UNKNOWN); | |
7 | 11 | } |
8 | 12 | |
9 | 13 |
1 | 1 | |
2 | 2 | void Stealth::suspend() |
3 | 3 | { |
4 | logMsg("is suspended"); | |
4 | m2 << "received SUSPEND request" << endl; | |
5 | 5 | |
6 | mailLogs(); | |
7 | d_stealthLog.refresh(); | |
8 | ||
9 | while (true) | |
10 | { | |
11 | d_ipc.wait(); | |
12 | if (d_run.mode(RESUME | TERMINATE)) | |
13 | break; | |
14 | m2 << "ignoring wake up signal in SUSPEND mode" << endl; | |
15 | } | |
16 | m2 << "received SUSPEND signal" << endl; | |
6 | timestamp("is suspended"); | |
17 | 7 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::suspendRequest() | |
2 | string Stealth::suspendRequest() | |
3 | 3 | { |
4 | if (d_run.mode(INTEGRITY_SCAN | WAIT | SUSPEND)) | |
5 | acceptMode(SUSPEND); | |
6 | else | |
7 | deniedMode("--suspend"); | |
4 | string ret; | |
5 | ||
6 | switch (d_task.mode()) | |
7 | { | |
8 | case INTEGRITY_SCAN: | |
9 | ret = acceptMode(SUSPEND); | |
10 | break; | |
11 | ||
12 | case SUSPEND: | |
13 | ret = "nop"; | |
14 | break; | |
15 | ||
16 | default: | |
17 | ret = deniedMode("--suspend"); | |
18 | break; | |
19 | } | |
20 | ||
21 | return ret; | |
8 | 22 | } |
0 | #include "stealth.ih" | |
1 | ||
2 | int LogReportbuf::sync() | |
3 | { | |
4 | d_report.flush(); | |
5 | d_report.mail(); | |
6 | return 0; | |
7 | } |
1 | 1 | |
2 | 2 | void Stealth::terminate() |
3 | 3 | { |
4 | logMsg("terminates"); | |
5 | d_run.setMode(LEAVE); | |
4 | timestamp("terminates"); | |
6 | 5 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::terminateRequest() | |
2 | string Stealth::terminateRequest() | |
3 | 3 | { |
4 | acceptMode(TERMINATE); | |
4 | return acceptMode(TERMINATE); | |
5 | 5 | } |
0 | 0 | #include "stealth.ih" |
1 | 1 | |
2 | void Stealth::unknownRequest() | |
2 | string Stealth::unknownRequest() | |
3 | 3 | { |
4 | 4 | ostringstream msg; |
5 | msg << "received undefined request `" << d_ipc.requestText() << '\''; | |
6 | 5 | |
7 | m2 << msg << endl; | |
8 | d_stealthLog << msg << endl; | |
6 | string ret("unknown request"); | |
7 | msg << "received " << ret; | |
9 | 8 | |
10 | d_request = false; | |
9 | m2 << msg.str() << endl; | |
10 | *d_report << msg.str() << endl; | |
11 | ||
12 | return ret; | |
11 | 13 | } |
12 | 14 | |
13 | 15 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::waitForKey() | |
3 | { | |
4 | cin.ignore(numeric_limits<int>::max(), '\n'); | |
5 | imsg << "STEALTH (foreground) TERMINATED by user-request" << endl; | |
6 | d_task.setMode(TERMINATE); | |
7 | d_job.notify(); | |
8 | } | |
9 |
0 | #include "stealth.ih" | |
1 | ||
2 | void Stealth::waitForRequest() | |
3 | { | |
4 | if (d_run.mode(WAIT)) | |
5 | { | |
6 | m1 << "MODE: WAIT" << endl; | |
7 | ||
8 | while (true) | |
9 | { | |
10 | d_ipc.timedWait(); | |
11 | if (d_ipc.timeout() || d_request) // wait for the next request | |
12 | break; // or timeout | |
13 | } | |
14 | ||
15 | if (d_run.mode(WAIT)) | |
16 | d_run.setMode(INTEGRITY_SCAN); | |
17 | } | |
18 | } |
0 | 0 | oxref by Frank B. Brokken (f.b.brokken@rug.nl) |
1 | oxref V1.00.01 2012-2013 | |
2 | ||
3 | CREATED Fri, 29 Aug 2014 09:48:55 +0000 | |
1 | oxref V1.00.02 2012-2015 | |
2 | ||
3 | CREATED Sat, 14 Feb 2015 15:43:45 +0000 | |
4 | 4 | CROSS REFERENCE FOR: -fxs tmp/libmodules.a |
5 | 5 | ---------------------------------------------------------------------- |
6 | ||
7 | absPath(std::string const&, std::string&) | |
8 | Full name: Util::absPath(std::string const&, std::string&) | |
9 | Source: abspath.cc | |
10 | Used By: | |
11 | options1.cc: Options::Options() | |
12 | setlog.cc: Options::setLog() | |
13 | setpolicypath.cc: Options::setPolicyPath() | |
14 | setskipfile.cc: Options::setSkipFile() | |
15 | fixrelativelocations.cc: PolicyFile::fixRelativeLocations() | |
6 | 16 | |
7 | 17 | acceptMode(StealthEnums::Mode) |
8 | 18 | Full name: Stealth::acceptMode(StealthEnums::Mode) |
20 | 30 | Used By: |
21 | 31 | setskip.cc: IntegrityScanner::setSkip() |
22 | 32 | |
33 | autoScan(char const*) | |
34 | Full name: Stealth::autoScan(char const*) | |
35 | Source: autoscan.cc | |
36 | Used By: | |
37 | reload.cc: Stealth::reload() | |
38 | rerun.cc: Stealth::rerun() | |
39 | resume.cc: Stealth::resume() | |
40 | ||
41 | chdirBase() const | |
42 | Full name: PolicyFile::chdirBase() const | |
43 | Source: chdirbase.cc | |
44 | Used By: | |
45 | load.cc: PolicyFile::load() | |
46 | ||
23 | 47 | checkM(std::string const&, char const*) const |
24 | 48 | Full name: Options::checkM(std::string const&, char const*) const |
25 | 49 | Source: checkm.cc |
57 | 81 | Source: datetime.cc |
58 | 82 | Used By: |
59 | 83 | nodifferences.cc: IntegrityScanner::noDifferences(std::string const&, std::string const&) |
60 | ||
61 | defineSupportedSignals() | |
62 | Full name: Stealth::defineSupportedSignals() | |
63 | Source: definesupportedsignals.cc | |
64 | Used By: | |
65 | dochores.cc: Stealth::doChores() | |
66 | 84 | |
67 | 85 | deniedMode(char const*) |
68 | 86 | Full name: Stealth::deniedMode(char const*) |
86 | 104 | local.cc: IntegrityScanner::local(std::string const&) |
87 | 105 | remote.cc: IntegrityScanner::remote(std::string const&) |
88 | 106 | |
89 | doChores() | |
90 | Full name: Stealth::doChores() | |
91 | Source: dochores.cc | |
92 | Used By: | |
93 | childprocess.cc: Stealth::childProcess() | |
94 | processpolicy.cc: Stealth::processPolicy() | |
95 | ||
96 | 107 | doPlainCommand(FBB::Process&) |
97 | 108 | Full name: IntegrityScanner::doPlainCommand(FBB::Process&) |
98 | 109 | Source: doplaincommand.cc |
100 | 111 | local.cc: IntegrityScanner::local(std::string const&) |
101 | 112 | remote.cc: IntegrityScanner::remote(std::string const&) |
102 | 113 | |
114 | doTasks() | |
115 | Full name: Stealth::doTasks() | |
116 | Source: dotasks.cc | |
117 | Used By: | |
118 | childprocess.cc: Stealth::childProcess() | |
119 | policymode.cc: Stealth::policyMode() | |
120 | ||
103 | 121 | execute(std::string const&) |
104 | 122 | Full name: IntegrityScanner::execute(std::string const&) |
105 | 123 | Source: execute.cc |
111 | 129 | Full name: PolicyFile::fetchCommands() |
112 | 130 | Source: fetchcommands.cc |
113 | 131 | Used By: |
114 | reload.cc: PolicyFile::reload() | |
132 | load.cc: PolicyFile::load() | |
115 | 133 | |
116 | 134 | fileName(std::string const&) |
117 | 135 | Full name: IntegrityScanner::fileName(std::string const&) |
120 | 138 | get.cc: IntegrityScanner::get(std::string const&) |
121 | 139 | put.cc: IntegrityScanner::put(std::string const&) |
122 | 140 | |
141 | fixRelativeLocations() | |
142 | Full name: PolicyFile::fixRelativeLocations() | |
143 | Source: fixrelativelocations.cc | |
144 | Used By: | |
145 | fetchcommands.cc: PolicyFile::fetchCommands() | |
146 | ||
123 | 147 | foreground(unsigned int) |
124 | 148 | Full name: IntegrityScanner::foreground(unsigned int) |
125 | 149 | Source: foreground.cc |
139 | 163 | Used By: |
140 | 164 | execute.cc: IntegrityScanner::execute(std::string const&) |
141 | 165 | |
166 | getCwd() | |
167 | Full name: Options::getCwd() | |
168 | Source: getcwd.cc | |
169 | Used By: | |
170 | options1.cc: Options::Options() | |
171 | ||
142 | 172 | getPath(std::string const&) const |
143 | 173 | Full name: IntegrityScanner::getPath(std::string const&) const |
144 | 174 | Source: getpath.cc |
147 | 177 | nodifferences.cc: IntegrityScanner::noDifferences(std::string const&, std::string const&) |
148 | 178 | |
149 | 179 | hasMail() |
150 | Full name: StealthLog::hasMail() | |
180 | Full name: Report::hasMail() | |
151 | 181 | Source: hasmail.cc |
152 | 182 | Used By: |
153 | maillogs.cc: Stealth::mailLogs() | |
154 | ||
155 | headerLine() const | |
156 | Full name: StealthLog::headerLine() const | |
157 | Source: headerline.cc | |
158 | Used By: | |
159 | sendmail.cc: Stealth::sendMail() | |
183 | destructor.cc: Report::~Report() | |
184 | mail.cc: Report::mail() | |
185 | ||
186 | incomingRequest(std::istream&, std::ostream&) | |
187 | Full name: Stealth::incomingRequest(std::istream&, std::ostream&) | |
188 | Source: incomingrequest.cc | |
189 | Used By: | |
190 | ipcinterface.cc: Stealth::ipcInterface() | |
160 | 191 | |
161 | 192 | insert(FBB::LinearMap<std::string, std::string, std::allocator<std::pair<std::string const, std::string> > >&, std::string const&) |
162 | 193 | Full name: PolicyFile::insert(FBB::LinearMap<std::string, std::string, std::allocator<std::pair<std::string const, std::string> > >&, std::string const&) |
164 | 195 | Used By: |
165 | 196 | directivesandcommands.cc: PolicyFile::directivesAndCommands() |
166 | 197 | |
167 | instance() | |
168 | Full name: Options::instance() | |
169 | Source: instance.cc | |
170 | Used By: | |
171 | ipc1.cc: IPC::IPC() | |
172 | stealth1.cc: Stealth::Stealth() | |
173 | fetchcommands.cc: PolicyFile::fetchCommands() | |
174 | setmode.cc: RunMode::setMode(StealthEnums::Mode) | |
175 | open.cc: StealthLog::open(std::string const&) | |
176 | scanheader.cc: StealthLog::scanHeader() | |
177 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
178 | ||
179 | 198 | integrityScan() |
180 | 199 | Full name: Stealth::integrityScan() |
181 | 200 | Source: integrityscan.cc |
182 | 201 | Used By: |
183 | 202 | data.cc: GLOBALS data.cc 11data.o |
184 | 203 | |
185 | IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
186 | Full name: IntegrityScanner::IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
204 | IntegrityScanner(RunMode const&, Options&, PolicyFile&, std::ostream&) | |
205 | Full name: IntegrityScanner::IntegrityScanner(RunMode const&, Options&, PolicyFile&, std::ostream&) | |
187 | 206 | Source: integrityscanner1.cc |
188 | 207 | Used By: |
189 | policydepdatamembers.cc: Stealth::policyDepDataMembers() | |
190 | 208 | reload.cc: Stealth::reload() |
191 | ||
192 | IPC() | |
193 | Full name: IPC::IPC() | |
194 | Source: ipc1.cc | |
195 | Used By: | |
196 | stealth1.cc: Stealth::Stealth() | |
197 | ||
198 | leave(std::ostream&) | |
199 | Full name: StealthEnums::leave(std::ostream&) | |
200 | Source: leave.cc | |
201 | Used By: | |
202 | checksize.cc: IntegrityScanner::checkSize(std::string const&, long) | |
203 | copy.cc: IntegrityScanner::copy(FBB::Process&, std::string const&) | |
204 | execute.cc: IntegrityScanner::execute(std::string const&) | |
205 | get.cc: IntegrityScanner::get(std::string const&) | |
206 | nextcommand.cc: IntegrityScanner::nextCommand(std::ostream&, std::string const&) | |
207 | put.cc: IntegrityScanner::put(std::string const&) | |
208 | putcommand.cc: IntegrityScanner::putCommand(std::string const&, std::string const&) const | |
209 | read.cc: IntegrityScanner::read(FBB::Process&, std::string const&) | |
210 | sameoutput.cc: IntegrityScanner::sameOutput(std::string const&, FBB::Process&) | |
211 | testexitvalue.cc: IntegrityScanner::testExitValue(std::string const&, std::string const&) | |
212 | write.cc: IntegrityScanner::write(std::string const&) | |
213 | ||
214 | loadPolicyOptions() | |
215 | Full name: Options::loadPolicyOptions() | |
216 | Source: loadpolicyoptions.cc | |
217 | Used By: | |
218 | options1.cc: Options::Options() | |
209 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
210 | ||
211 | ipcInterface() | |
212 | Full name: Stealth::ipcInterface() | |
213 | Source: ipcinterface.cc | |
214 | Used By: | |
215 | childprocess.cc: Stealth::childProcess() | |
216 | ||
217 | jobsHandler() | |
218 | Full name: Stealth::jobsHandler() | |
219 | Source: jobshandler.cc | |
220 | Used By: | |
221 | dotasks.cc: Stealth::doTasks() | |
222 | ||
223 | load() | |
224 | Full name: PolicyFile::load() | |
225 | Source: load.cc | |
226 | Used By: | |
227 | policyfile1.cc: PolicyFile::PolicyFile(Options&) | |
228 | ||
229 | loadOptions(FBB::ConfigFile&, unsigned int) | |
230 | Full name: PolicyFile::loadOptions(FBB::ConfigFile&, unsigned int) | |
231 | Source: loadoptions.cc | |
232 | Used By: | |
233 | directivesandcommands.cc: PolicyFile::directivesAndCommands() | |
219 | 234 | |
220 | 235 | loadSkipFiles() |
221 | 236 | Full name: IntegrityScanner::loadSkipFiles() |
222 | 237 | Source: loadskipfiles.cc |
223 | 238 | Used By: |
224 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
239 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode const&, Options&, PolicyFile&, std::ostream&) | |
225 | 240 | |
226 | 241 | local(std::string const&) |
227 | 242 | Full name: IntegrityScanner::local(std::string const&) |
229 | 244 | Used By: |
230 | 245 | execute.cc: IntegrityScanner::execute(std::string const&) |
231 | 246 | |
232 | logMsg(char const*) | |
233 | Full name: Stealth::logMsg(char const*) | |
234 | Source: logmsg.cc | |
235 | Used By: | |
236 | reload.cc: Stealth::reload() | |
237 | suspend.cc: Stealth::suspend() | |
238 | terminate.cc: Stealth::terminate() | |
247 | LogReportbuf(Report&) | |
248 | Full name: LogReportbuf::LogReportbuf(Report&) | |
249 | Source: logreportbuf1.cc | |
250 | Used By: | |
251 | setupfatalreport.cc: Stealth::setupFatalReport() | |
252 | ||
253 | LogUnit(Options&) | |
254 | Full name: LogUnit::LogUnit(Options&) | |
255 | Source: logunit1.cc | |
256 | Used By: | |
257 | stealth1.cc: Stealth::Stealth() | |
239 | 258 | |
240 | 259 | m1 |
241 | 260 | Full name: m1 |
242 | 261 | Source: data.cc |
243 | 262 | Used By: |
244 | 263 | childprocess.cc: Stealth::childProcess() |
245 | processrequests.cc: Stealth::processRequests() | |
246 | waitforrequest.cc: Stealth::waitForRequest() | |
264 | dotasks.cc: Stealth::doTasks() | |
265 | jobshandler.cc: Stealth::jobsHandler() | |
247 | 266 | setverbosity.cc: Msg::setVerbosity(unsigned int) |
248 | options1.cc: Options::Options() | |
249 | 267 | execute.cc: IntegrityScanner::execute(std::string const&) |
250 | 268 | nodifferences.cc: IntegrityScanner::noDifferences(std::string const&, std::string const&) |
251 | 269 | run.cc: IntegrityScanner::run() |
254 | 272 | Full name: m2 |
255 | 273 | Source: data.cc |
256 | 274 | Used By: |
257 | sendrequest.cc: IPC::sendRequest(char const*, int) | |
258 | sendrequestor.cc: IPC::sendRequestor(std::string const&) | |
259 | signaldaemon.cc: IPC::signalDaemon() | |
260 | timedwait.cc: IPC::timedWait() | |
261 | wait.cc: IPC::wait(bool) | |
262 | writerunfile.cc: IPC::writeRunFile(int) | |
275 | autoscan.cc: Stealth::autoScan(char const*) | |
263 | 276 | deniedmode.cc: Stealth::deniedMode(char const*) |
264 | resume.cc: Stealth::resume() | |
277 | integrityscan.cc: Stealth::integrityScan() | |
278 | ipcinterface.cc: Stealth::ipcInterface() | |
279 | nextjob.cc: Stealth::nextJob() | |
280 | reload.cc: Stealth::reload() | |
281 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
265 | 282 | suspend.cc: Stealth::suspend() |
266 | 283 | unknownrequest.cc: Stealth::unknownRequest() |
267 | 284 | setverbosity.cc: Msg::setVerbosity(unsigned int) |
268 | waitfor.cc: Wait11::waitFor(unsigned int, bool) | |
269 | waitsignal.cc: Wait11::waitSignal(bool) | |
270 | reload.cc: PolicyFile::reload() | |
271 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
272 | 285 | startcommandshells.cc: IntegrityScanner::startCommandShells() |
273 | 286 | |
274 | 287 | m3 |
275 | 288 | Full name: m3 |
276 | 289 | Source: data.cc |
277 | 290 | Used By: |
278 | maillogs.cc: Stealth::mailLogs() | |
279 | sendmail.cc: Stealth::sendMail() | |
291 | reload.cc: Stealth::reload() | |
292 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
280 | 293 | setverbosity.cc: Msg::setVerbosity(unsigned int) |
294 | mail.cc: Report::mail() | |
295 | sendmail.cc: Report::sendMail() | |
281 | 296 | copy.cc: IntegrityScanner::copy(FBB::Process&, std::string const&) |
282 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
283 | 297 | loadskipfiles.cc: IntegrityScanner::loadSkipFiles() |
284 | 298 | nextcommand.cc: IntegrityScanner::nextCommand(std::ostream&, std::string const&) |
285 | 299 | nodifferences.cc: IntegrityScanner::noDifferences(std::string const&, std::string const&) |
291 | 305 | waitforsentinel.cc: IntegrityScanner::waitForSentinel(FBB::Process&) |
292 | 306 | write.cc: IntegrityScanner::write(std::string const&) |
293 | 307 | |
294 | mailLogs() | |
295 | Full name: Stealth::mailLogs() | |
296 | Source: maillogs.cc | |
297 | Used By: | |
298 | processrequests.cc: Stealth::processRequests() | |
299 | reload.cc: Stealth::reload() | |
300 | suspend.cc: Stealth::suspend() | |
308 | mail() | |
309 | Full name: Report::mail() | |
310 | Source: mail.cc | |
311 | Used By: | |
312 | ipcinterface.cc: Stealth::ipcInterface() | |
313 | jobshandler.cc: Stealth::jobsHandler() | |
314 | timestamp.cc: Report::timestamp(char const*, unsigned int) | |
315 | sync.cc: LogReportbuf::sync() | |
301 | 316 | |
302 | 317 | mkdir(std::string const&) |
303 | 318 | Full name: Util::mkdir(std::string const&) |
304 | 319 | Source: mkdir.cc |
305 | 320 | Used By: |
306 | reload.cc: PolicyFile::reload() | |
321 | load.cc: PolicyFile::load() | |
307 | 322 | sameoutput.cc: IntegrityScanner::sameOutput(std::string const&, FBB::Process&) |
308 | 323 | |
309 | 324 | mp |
320 | 335 | Full name: Msg::Msg() |
321 | 336 | Source: msg1.cc |
322 | 337 | Used By: |
323 | data.cc: GLOBALS data.cc 1data.o | |
338 | data.cc: GLOBALS data.cc 2data.o | |
324 | 339 | |
325 | 340 | Msg(std::ostream&) |
326 | 341 | Full name: Msg::Msg(std::ostream&) |
327 | 342 | Source: msg2.cc |
328 | 343 | Used By: |
329 | data.cc: GLOBALS data.cc 1data.o | |
344 | data.cc: GLOBALS data.cc 2data.o | |
345 | ||
346 | newLog() | |
347 | Full name: LogUnit::newLog() | |
348 | Source: newlog.cc | |
349 | Used By: | |
350 | setuplogs.cc: LogUnit::setupLogs() | |
351 | ||
352 | newSyslogStream() | |
353 | Full name: LogUnit::newSyslogStream() | |
354 | Source: newsyslogstream.cc | |
355 | Used By: | |
356 | setuplogs.cc: LogUnit::setupLogs() | |
330 | 357 | |
331 | 358 | nextCommand(std::ostream&, std::string const&) |
332 | 359 | Full name: IntegrityScanner::nextCommand(std::ostream&, std::string const&) |
336 | 363 | doplaincommand.cc: IntegrityScanner::doPlainCommand(FBB::Process&) |
337 | 364 | get.cc: IntegrityScanner::get(std::string const&) |
338 | 365 | |
366 | nextJob() | |
367 | Full name: Stealth::nextJob() | |
368 | Source: nextjob.cc | |
369 | Used By: | |
370 | jobshandler.cc: Stealth::jobsHandler() | |
371 | ||
339 | 372 | noDifferences(std::string const&, std::string const&) |
340 | 373 | Full name: IntegrityScanner::noDifferences(std::string const&, std::string const&) |
341 | 374 | Source: nodifferences.cc |
342 | 375 | Used By: |
343 | 376 | sameoutput.cc: IntegrityScanner::sameOutput(std::string const&, FBB::Process&) |
344 | 377 | |
345 | notify() | |
346 | Full name: Wait11::notify() | |
347 | Source: notify.cc | |
348 | Used By: | |
349 | signalhandler.cc: Stealth::signalHandler(unsigned int) | |
378 | notifyTask() | |
379 | Full name: Stealth::notifyTask() | |
380 | Source: notifytask.cc | |
381 | Used By: | |
382 | ipcinterface.cc: Stealth::ipcInterface() | |
350 | 383 | |
351 | 384 | oldOptions() const |
352 | 385 | Full name: Options::oldOptions() const |
354 | 387 | Used By: |
355 | 388 | options1.cc: Options::Options() |
356 | 389 | |
357 | open(std::string const&) | |
358 | Full name: StealthLog::open(std::string const&) | |
359 | Source: open.cc | |
360 | Used By: | |
361 | policydepdatamembers.cc: Stealth::policyDepDataMembers() | |
362 | reload.cc: Stealth::reload() | |
363 | ||
364 | 390 | Options() |
365 | 391 | Full name: Options::Options() |
366 | 392 | Source: options1.cc |
367 | 393 | Used By: |
368 | instance.cc: Options::instance() | |
394 | stealth1.cc: Stealth::Stealth() | |
369 | 395 | |
370 | 396 | parentProcess() |
371 | 397 | Full name: Stealth::parentProcess() |
373 | 399 | Used By: |
374 | 400 | destructor.cc: Stealth::~Stealth() |
375 | 401 | |
376 | policyDepDataMembers() | |
377 | Full name: Stealth::policyDepDataMembers() | |
378 | Source: policydepdatamembers.cc | |
379 | Used By: | |
380 | dochores.cc: Stealth::doChores() | |
381 | ||
382 | PolicyFile(std::string const&) | |
383 | Full name: PolicyFile::PolicyFile(std::string const&) | |
402 | PolicyFile(Options&) | |
403 | Full name: PolicyFile::PolicyFile(Options&) | |
384 | 404 | Source: policyfile1.cc |
385 | 405 | Used By: |
386 | policydepdatamembers.cc: Stealth::policyDepDataMembers() | |
387 | ||
388 | process(StealthEnums::Mode) | |
389 | Full name: Stealth::process(StealthEnums::Mode) | |
390 | Source: process.cc | |
391 | Used By: | |
392 | processrequests.cc: Stealth::processRequests() | |
406 | reload.cc: Stealth::reload() | |
407 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
393 | 408 | |
394 | 409 | processMail() |
395 | Full name: Stealth::processMail() | |
410 | Full name: Report::processMail() | |
396 | 411 | Source: processmail.cc |
397 | 412 | Used By: |
398 | maillogs.cc: Stealth::mailLogs() | |
399 | ||
400 | processRequests() | |
401 | Full name: Stealth::processRequests() | |
402 | Source: processrequests.cc | |
403 | Used By: | |
404 | dochores.cc: Stealth::doChores() | |
413 | destructor.cc: Report::~Report() | |
414 | mail.cc: Report::mail() | |
405 | 415 | |
406 | 416 | put(std::string const&) |
407 | 417 | Full name: IntegrityScanner::put(std::string const&) |
419 | 429 | Full name: Options::randomAddition() const |
420 | 430 | Source: randomaddition.cc |
421 | 431 | Used By: |
422 | timedwait.cc: IPC::timedWait() | |
432 | nextjob.cc: Stealth::nextJob() | |
423 | 433 | |
424 | 434 | read(FBB::Process&, std::string const&) |
425 | 435 | Full name: IntegrityScanner::read(FBB::Process&, std::string const&) |
427 | 437 | Used By: |
428 | 438 | get.cc: IntegrityScanner::get(std::string const&) |
429 | 439 | |
430 | readDaemonPid() | |
431 | Full name: IPC::readDaemonPid() | |
432 | Source: readdaemonpid.cc | |
433 | Used By: | |
434 | signaldaemon.cc: IPC::signalDaemon() | |
435 | ||
436 | 440 | realPath(std::string const&) |
437 | 441 | Full name: Util::realPath(std::string const&) |
438 | 442 | Source: realpath.cc |
439 | 443 | Used By: |
440 | loadpolicyoptions.cc: Options::loadPolicyOptions() | |
444 | abspath.cc: Util::absPath(std::string const&, std::string&) | |
441 | 445 | |
442 | 446 | refresh() |
443 | Full name: StealthLog::refresh() | |
447 | Full name: Report::refresh() | |
444 | 448 | Source: refresh.cc |
445 | 449 | Used By: |
446 | processrequests.cc: Stealth::processRequests() | |
447 | suspend.cc: Stealth::suspend() | |
448 | ||
449 | reload() | |
450 | Full name: PolicyFile::reload() | |
451 | Source: reload.cc | |
452 | Used By: | |
453 | reload.cc: Stealth::reload() | |
454 | policyfile1.cc: PolicyFile::PolicyFile(std::string const&) | |
450 | processmail.cc: Report::processMail() | |
451 | report1.cc: Report::Report(Options&, PolicyFile const&) | |
455 | 452 | |
456 | 453 | reload() |
457 | 454 | Full name: Stealth::reload() |
498 | 495 | Used By: |
499 | 496 | fetchcommands.cc: PolicyFile::fetchCommands() |
500 | 497 | |
501 | request() | |
502 | Full name: IPC::request() | |
503 | Source: request.cc | |
504 | Used By: | |
505 | signalhandler.cc: Stealth::signalHandler(unsigned int) | |
498 | Report(Options&, PolicyFile const&) | |
499 | Full name: Report::Report(Options&, PolicyFile const&) | |
500 | Source: report1.cc | |
501 | Used By: | |
502 | reload.cc: Stealth::reload() | |
503 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
506 | 504 | |
507 | 505 | requireSomeArgument() |
508 | 506 | Full name: Options::requireSomeArgument() |
510 | 508 | Used By: |
511 | 509 | options1.cc: Options::Options() |
512 | 510 | |
511 | rerun() | |
512 | Full name: Stealth::rerun() | |
513 | Source: rerun.cc | |
514 | Used By: | |
515 | data.cc: GLOBALS data.cc 11data.o | |
516 | ||
513 | 517 | rerunRequest() |
514 | 518 | Full name: Stealth::rerunRequest() |
515 | 519 | Source: rerunrequest.cc |
529 | 533 | data.cc: GLOBALS data.cc 11data.o |
530 | 534 | |
531 | 535 | rewind() |
532 | Full name: StealthLog::rewind() | |
536 | Full name: Report::rewind() | |
533 | 537 | Source: rewind.cc |
534 | 538 | Used By: |
535 | processmail.cc: Stealth::processMail() | |
536 | sendmail.cc: Stealth::sendMail() | |
539 | processmail.cc: Report::processMail() | |
540 | sendmail.cc: Report::sendMail() | |
537 | 541 | |
538 | 542 | rfc2822() const |
539 | 543 | Full name: Options::rfc2822() const |
540 | 544 | Source: rfc2822.cc |
541 | 545 | Used By: |
542 | logmsg.cc: Stealth::logMsg(char const*) | |
546 | rerun.cc: Stealth::rerun() | |
543 | 547 | resume.cc: Stealth::resume() |
544 | open.cc: StealthLog::open(std::string const&) | |
545 | scanheader.cc: StealthLog::scanHeader() | |
548 | report1.cc: Report::Report(Options&, PolicyFile const&) | |
549 | scanheader.cc: Report::scanHeader() | |
550 | timestamp.cc: Report::timestamp(char const*, unsigned int) | |
546 | 551 | |
547 | 552 | run() |
548 | 553 | Full name: IntegrityScanner::run() |
557 | 562 | directivesandcommands.cc: PolicyFile::directivesAndCommands() |
558 | 563 | |
559 | 564 | s_configFileBase |
560 | Full name: Options::s_configFileBase | |
561 | Source: data.cc | |
562 | Used By: | |
563 | loadpolicyoptions.cc: Options::loadPolicyOptions() | |
565 | Full name: PolicyFile::s_configFileBase | |
566 | Source: data.cc | |
567 | Used By: | |
568 | loadoptions.cc: PolicyFile::loadOptions(FBB::ConfigFile&, unsigned int) | |
564 | 569 | |
565 | 570 | s_defaultKeyword |
566 | 571 | Full name: PolicyFile::s_defaultKeyword |
567 | 572 | Source: data.cc |
568 | 573 | Used By: |
569 | reload.cc: PolicyFile::reload() | |
574 | load.cc: PolicyFile::load() | |
570 | 575 | |
571 | 576 | s_defaultSyslogFacility |
572 | 577 | Full name: Options::s_defaultSyslogFacility |
573 | 578 | Source: data.cc |
574 | 579 | Used By: |
575 | syslogfacility.cc: Options::syslogFacility() const | |
580 | setsyslogfacility.cc: Options::setSyslogFacility() | |
576 | 581 | |
577 | 582 | s_defaultSyslogIdent |
578 | 583 | Full name: Options::s_defaultSyslogIdent |
579 | 584 | Source: data.cc |
580 | 585 | Used By: |
581 | syslogtag.cc: Options::syslogTag() const | |
586 | setsyslog.cc: Options::setSyslog() | |
582 | 587 | usage.cc: Options::usage(std::string const&) |
583 | 588 | |
584 | 589 | s_defaultSyslogPriority |
585 | 590 | Full name: Options::s_defaultSyslogPriority |
586 | 591 | Source: data.cc |
587 | 592 | Used By: |
588 | syslogpriority.cc: Options::syslogPriority() const | |
593 | setsyslogpriority.cc: Options::setSyslogPriority() | |
589 | 594 | |
590 | 595 | s_defaultVerbosity |
591 | 596 | Full name: Options::s_defaultVerbosity |
592 | 597 | Source: data.cc |
593 | 598 | Used By: |
594 | setverbosity.cc: Options::setVerbosity(bool, std::string const&) | |
599 | setverbosity.cc: Options::setVerbosity() | |
595 | 600 | |
596 | 601 | s_define |
597 | 602 | Full name: PolicyFile::s_define |
604 | 609 | Source: data.cc |
605 | 610 | Used By: |
606 | 611 | testexitvalue.cc: IntegrityScanner::testExitValue(std::string const&, std::string const&) |
612 | ||
613 | s_firstWord | |
614 | Full name: PolicyFile::s_firstWord | |
615 | Source: data.cc | |
616 | Used By: | |
617 | directivesandcommands.cc: PolicyFile::directivesAndCommands() | |
618 | insert.cc: PolicyFile::insert(FBB::LinearMap<std::string, std::string, std::allocator<std::pair<std::string const, std::string> > >&, std::string const&) | |
607 | 619 | |
608 | 620 | s_firstWord |
609 | 621 | Full name: IntegrityScanner::s_firstWord |
619 | 631 | removefirstword.cc: IntegrityScanner::removeFirstWord(char const*) |
620 | 632 | removelog.cc: IntegrityScanner::removeLOG() |
621 | 633 | |
622 | s_firstWord | |
623 | Full name: PolicyFile::s_firstWord | |
624 | Source: data.cc | |
625 | Used By: | |
626 | directivesandcommands.cc: PolicyFile::directivesAndCommands() | |
627 | insert.cc: PolicyFile::insert(FBB::LinearMap<std::string, std::string, std::allocator<std::pair<std::string const, std::string> > >&, std::string const&) | |
634 | s_log | |
635 | Full name: PolicyFile::s_log | |
636 | Source: data.cc | |
637 | Used By: | |
638 | fixrelativelocations.cc: PolicyFile::fixRelativeLocations() | |
628 | 639 | |
629 | 640 | s_modeName |
630 | 641 | Full name: RunMode::s_modeName |
631 | 642 | Source: data.cc |
632 | 643 | Used By: |
633 | 644 | deniedmode.cc: Stealth::deniedMode(char const*) |
634 | processrequests.cc: Stealth::processRequests() | |
645 | jobshandler.cc: Stealth::jobsHandler() | |
635 | 646 | run.cc: IntegrityScanner::run() |
636 | ||
637 | s_modeName | |
638 | Full name: Options::s_modeName | |
639 | Source: data.cc | |
640 | Used By: | |
641 | signaldaemon.cc: IPC::signalDaemon() | |
642 | 647 | |
643 | 648 | s_nDefaultKeywords |
644 | 649 | Full name: PolicyFile::s_nDefaultKeywords |
645 | 650 | Source: data.cc |
646 | 651 | Used By: |
647 | reload.cc: PolicyFile::reload() | |
648 | ||
649 | s_options | |
650 | Full name: Options::s_options | |
651 | Source: data.cc | |
652 | Used By: | |
653 | instance.cc: Options::instance() | |
654 | ||
655 | s_request | |
656 | Full name: IPC::s_request | |
657 | Source: data.cc | |
658 | Used By: | |
659 | request.cc: IPC::request() | |
652 | load.cc: PolicyFile::load() | |
660 | 653 | |
661 | 654 | s_request |
662 | 655 | Full name: Stealth::s_request |
663 | 656 | Source: data.cc |
664 | 657 | Used By: |
665 | signalhandler.cc: Stealth::signalHandler(unsigned int) | |
658 | incomingrequest.cc: Stealth::incomingRequest(std::istream&, std::ostream&) | |
666 | 659 | |
667 | 660 | s_syslogFacilities |
668 | 661 | Full name: Options::s_syslogFacilities |
669 | 662 | Source: data.cc |
670 | 663 | Used By: |
671 | syslogfacility.cc: Options::syslogFacility() const | |
664 | setsyslogfacility.cc: Options::setSyslogFacility() | |
672 | 665 | |
673 | 666 | s_syslogPriorities |
674 | 667 | Full name: Options::s_syslogPriorities |
675 | 668 | Source: data.cc |
676 | 669 | Used By: |
677 | syslogpriority.cc: Options::syslogPriority() const | |
670 | setsyslogpriority.cc: Options::setSyslogPriority() | |
678 | 671 | |
679 | 672 | s_task |
680 | 673 | Full name: Stealth::s_task |
681 | 674 | Source: data.cc |
682 | 675 | Used By: |
683 | process.cc: Stealth::process(StealthEnums::Mode) | |
676 | jobshandler.cc: Stealth::jobsHandler() | |
684 | 677 | |
685 | 678 | sameOutput(std::string const&, FBB::Process&) |
686 | 679 | Full name: IntegrityScanner::sameOutput(std::string const&, FBB::Process&) |
689 | 682 | docheckcommand.cc: IntegrityScanner::doCHECKcommand(FBB::Process&) |
690 | 683 | |
691 | 684 | scanHeader() |
692 | Full name: StealthLog::scanHeader() | |
685 | Full name: Report::scanHeader() | |
693 | 686 | Source: scanheader.cc |
694 | 687 | Used By: |
695 | 688 | integrityscan.cc: Stealth::integrityScan() |
696 | 689 | |
697 | 690 | sendMail() |
698 | Full name: Stealth::sendMail() | |
691 | Full name: Report::sendMail() | |
699 | 692 | Source: sendmail.cc |
700 | 693 | Used By: |
701 | processmail.cc: Stealth::processMail() | |
702 | ||
703 | sendRequest(char const*, int) | |
704 | Full name: IPC::sendRequest(char const*, int) | |
705 | Source: sendrequest.cc | |
706 | Used By: | |
707 | signaldaemon.cc: IPC::signalDaemon() | |
708 | ||
709 | sendRequestor(std::string const&) | |
710 | Full name: IPC::sendRequestor(std::string const&) | |
711 | Source: sendrequestor.cc | |
712 | Used By: | |
713 | acceptmode.cc: Stealth::acceptMode(StealthEnums::Mode) | |
714 | deniedmode.cc: Stealth::deniedMode(char const*) | |
694 | processmail.cc: Report::processMail() | |
715 | 695 | |
716 | 696 | setCommandNr() |
717 | 697 | Full name: Options::setCommandNr() |
719 | 699 | Used By: |
720 | 700 | options1.cc: Options::Options() |
721 | 701 | |
702 | setConfigOptions() | |
703 | Full name: Options::setConfigOptions() | |
704 | Source: setconfigoptions.cc | |
705 | Used By: | |
706 | options1.cc: Options::Options() | |
707 | loadoptions.cc: PolicyFile::loadOptions(FBB::ConfigFile&, unsigned int) | |
708 | ||
722 | 709 | setDownloadSize() |
723 | 710 | Full name: Options::setDownloadSize() |
724 | 711 | Source: setdownloadsize.cc |
725 | 712 | Used By: |
726 | options1.cc: Options::Options() | |
713 | setconfigoptions.cc: Options::setConfigOptions() | |
727 | 714 | |
728 | 715 | setLog() |
729 | 716 | Full name: Options::setLog() |
730 | 717 | Source: setlog.cc |
731 | 718 | Used By: |
732 | 719 | options1.cc: Options::Options() |
720 | setconfigoptions.cc: Options::setConfigOptions() | |
733 | 721 | |
734 | 722 | setMail() |
735 | 723 | Full name: Options::setMail() |
736 | 724 | Source: setmail.cc |
737 | 725 | Used By: |
738 | options1.cc: Options::Options() | |
726 | setconfigoptions.cc: Options::setConfigOptions() | |
739 | 727 | |
740 | 728 | setMode() |
741 | 729 | Full name: Options::setMode() |
748 | 736 | Source: setmode.cc |
749 | 737 | Used By: |
750 | 738 | acceptmode.cc: Stealth::acceptMode(StealthEnums::Mode) |
751 | integrityscan.cc: Stealth::integrityScan() | |
752 | reload.cc: Stealth::reload() | |
753 | resume.cc: Stealth::resume() | |
739 | autoscan.cc: Stealth::autoScan(char const*) | |
740 | incomingrequest.cc: Stealth::incomingRequest(std::istream&, std::ostream&) | |
741 | ipcinterface.cc: Stealth::ipcInterface() | |
742 | nextjob.cc: Stealth::nextJob() | |
743 | notifytask.cc: Stealth::notifyTask() | |
754 | 744 | stealth1.cc: Stealth::Stealth() |
755 | terminate.cc: Stealth::terminate() | |
756 | waitforrequest.cc: Stealth::waitForRequest() | |
757 | read.cc: IntegrityScanner::read(FBB::Process&, std::string const&) | |
745 | waitforkey.cc: Stealth::waitForKey() | |
758 | 746 | |
759 | 747 | setParsePolicy() |
760 | 748 | Full name: Options::setParsePolicy() |
762 | 750 | Used By: |
763 | 751 | options1.cc: Options::Options() |
764 | 752 | |
753 | setPolicyPath() | |
754 | Full name: Options::setPolicyPath() | |
755 | Source: setpolicypath.cc | |
756 | Used By: | |
757 | options1.cc: Options::Options() | |
758 | ||
765 | 759 | setRandomDelay() |
766 | 760 | Full name: Options::setRandomDelay() |
767 | 761 | Source: setrandomdelay.cc |
768 | 762 | Used By: |
769 | options1.cc: Options::Options() | |
763 | setconfigoptions.cc: Options::setConfigOptions() | |
770 | 764 | |
771 | 765 | setRepeat() |
772 | 766 | Full name: Options::setRepeat() |
773 | 767 | Source: setrepeat.cc |
774 | 768 | Used By: |
775 | options1.cc: Options::Options() | |
769 | setconfigoptions.cc: Options::setConfigOptions() | |
776 | 770 | |
777 | 771 | setSentinel() |
778 | 772 | Full name: IntegrityScanner::setSentinel() |
779 | 773 | Source: setsentinel.cc |
780 | 774 | Used By: |
781 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode&, PolicyFile&, std::ostream&) | |
775 | integrityscanner1.cc: IntegrityScanner::IntegrityScanner(RunMode const&, Options&, PolicyFile&, std::ostream&) | |
782 | 776 | run.cc: IntegrityScanner::run() |
783 | 777 | |
784 | 778 | setSkip() |
787 | 781 | Used By: |
788 | 782 | loadskipfiles.cc: IntegrityScanner::loadSkipFiles() |
789 | 783 | |
790 | setSkipFilePath() | |
791 | Full name: Options::setSkipFilePath() | |
792 | Source: setskipfilepath.cc | |
793 | Used By: | |
794 | options1.cc: Options::Options() | |
784 | setSkipFile() | |
785 | Full name: Options::setSkipFile() | |
786 | Source: setskipfile.cc | |
787 | Used By: | |
788 | options1.cc: Options::Options() | |
789 | setconfigoptions.cc: Options::setConfigOptions() | |
795 | 790 | |
796 | 791 | setStdout() |
797 | 792 | Full name: Options::setStdout() |
798 | 793 | Source: setstdout.cc |
799 | 794 | Used By: |
800 | options1.cc: Options::Options() | |
795 | setconfigoptions.cc: Options::setConfigOptions() | |
801 | 796 | |
802 | 797 | setSyslog() |
803 | 798 | Full name: Options::setSyslog() |
804 | 799 | Source: setsyslog.cc |
805 | 800 | Used By: |
806 | options1.cc: Options::Options() | |
801 | setconfigoptions.cc: Options::setConfigOptions() | |
802 | ||
803 | setSyslogFacility() | |
804 | Full name: Options::setSyslogFacility() | |
805 | Source: setsyslogfacility.cc | |
806 | Used By: | |
807 | setsyslog.cc: Options::setSyslog() | |
808 | ||
809 | setSyslogPriority() | |
810 | Full name: Options::setSyslogPriority() | |
811 | Source: setsyslogpriority.cc | |
812 | Used By: | |
813 | setsyslog.cc: Options::setSyslog() | |
807 | 814 | |
808 | 815 | setTimestamp() |
809 | 816 | Full name: Options::setTimestamp() |
810 | 817 | Source: settimestamp.cc |
811 | 818 | Used By: |
812 | options1.cc: Options::Options() | |
813 | ||
814 | setVerbosity(bool, std::string const&) | |
815 | Full name: Options::setVerbosity(bool, std::string const&) | |
819 | setconfigoptions.cc: Options::setConfigOptions() | |
820 | ||
821 | setUniquePtrs() | |
822 | Full name: Stealth::setUniquePtrs() | |
823 | Source: setuniqueptrs.cc | |
824 | Used By: | |
825 | policymode.cc: Stealth::policyMode() | |
826 | ||
827 | setupFatalReport() | |
828 | Full name: Stealth::setupFatalReport() | |
829 | Source: setupfatalreport.cc | |
830 | Used By: | |
831 | reload.cc: Stealth::reload() | |
832 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
833 | ||
834 | setupLogs() | |
835 | Full name: LogUnit::setupLogs() | |
836 | Source: setuplogs.cc | |
837 | Used By: | |
838 | setuplogs2.cc: LogUnit::setupLogs(std::ostream&) | |
839 | policymode.cc: Stealth::policyMode() | |
840 | ||
841 | setupLogs(std::ostream&) | |
842 | Full name: LogUnit::setupLogs(std::ostream&) | |
843 | Source: setuplogs2.cc | |
844 | Used By: | |
845 | reload.cc: Stealth::reload() | |
846 | setuniqueptrs.cc: Stealth::setUniquePtrs() | |
847 | ||
848 | setVerbosity() | |
849 | Full name: Options::setVerbosity() | |
816 | 850 | Source: setverbosity.cc |
817 | 851 | Used By: |
818 | options1.cc: Options::Options() | |
852 | setconfigoptions.cc: Options::setConfigOptions() | |
819 | 853 | |
820 | 854 | setVerbosity(unsigned int) |
821 | 855 | Full name: Msg::setVerbosity(unsigned int) |
822 | 856 | Source: setverbosity.cc |
823 | 857 | Used By: |
824 | setverbosity.cc: Options::setVerbosity(bool, std::string const&) | |
825 | ||
826 | signalDaemon() | |
827 | Full name: IPC::signalDaemon() | |
828 | Source: signaldaemon.cc | |
829 | Used By: | |
830 | contactpeer.cc: Stealth::contactPeer() | |
831 | ||
832 | signalHandler(unsigned int) | |
833 | Full name: Stealth::signalHandler(unsigned int) | |
834 | Source: signalhandler.cc | |
835 | Used By: | |
836 | destructor.cc: Stealth::~Stealth() | |
858 | setverbosity.cc: Options::setVerbosity() | |
837 | 859 | |
838 | 860 | skip(std::string&) |
839 | 861 | Full name: IntegrityScanner::skip(std::string&) |
851 | 873 | Full name: IntegrityScanner::startCommandShells() |
852 | 874 | Source: startcommandshells.cc |
853 | 875 | Used By: |
854 | dochores.cc: Stealth::doChores() | |
876 | dotasks.cc: Stealth::doTasks() | |
855 | 877 | reload.cc: Stealth::reload() |
856 | 878 | |
857 | 879 | suspend() |
866 | 888 | Used By: |
867 | 889 | data.cc: GLOBALS data.cc 11data.o |
868 | 890 | |
869 | syslogFacility() const | |
870 | Full name: Options::syslogFacility() const | |
871 | Source: syslogfacility.cc | |
872 | Used By: | |
873 | setsyslog.cc: Options::setSyslog() | |
874 | ||
875 | syslogPriority() const | |
876 | Full name: Options::syslogPriority() const | |
877 | Source: syslogpriority.cc | |
878 | Used By: | |
879 | setsyslog.cc: Options::setSyslog() | |
880 | ||
881 | syslogTag() const | |
882 | Full name: Options::syslogTag() const | |
883 | Source: syslogtag.cc | |
884 | Used By: | |
885 | setsyslog.cc: Options::setSyslog() | |
891 | sync() | |
892 | Full name: LogReportbuf::sync() | |
893 | Source: sync.cc | |
894 | Used By: | |
895 | overflow.cc: LogReportbuf::overflow(int) | |
886 | 896 | |
887 | 897 | terminate() |
888 | 898 | Full name: Stealth::terminate() |
889 | 899 | Source: terminate.cc |
890 | 900 | Used By: |
891 | 901 | data.cc: GLOBALS data.cc 11data.o |
892 | process.cc: Stealth::process(StealthEnums::Mode) | |
893 | 902 | |
894 | 903 | terminateRequest() |
895 | 904 | Full name: Stealth::terminateRequest() |
905 | 914 | read.cc: IntegrityScanner::read(FBB::Process&, std::string const&) |
906 | 915 | waitforsentinel.cc: IntegrityScanner::waitForSentinel(FBB::Process&) |
907 | 916 | |
908 | timedWait() | |
909 | Full name: IPC::timedWait() | |
910 | Source: timedwait.cc | |
911 | Used By: | |
912 | waitforrequest.cc: Stealth::waitForRequest() | |
917 | timestamp(char const*, unsigned int) | |
918 | Full name: Report::timestamp(char const*, unsigned int) | |
919 | Source: timestamp.cc | |
920 | Used By: | |
921 | reload.cc: Stealth::reload() | |
922 | suspend.cc: Stealth::suspend() | |
923 | terminate.cc: Stealth::terminate() | |
913 | 924 | |
914 | 925 | unknownRequest() |
915 | 926 | Full name: Stealth::unknownRequest() |
929 | 940 | Used By: |
930 | 941 | oldoptions.cc: Options::oldOptions() const |
931 | 942 | usage.cc: Options::usage(std::string const&) |
932 | open.cc: StealthLog::open(std::string const&) | |
933 | ||
934 | wait(bool) | |
935 | Full name: IPC::wait(bool) | |
936 | Source: wait.cc | |
937 | Used By: | |
938 | suspend.cc: Stealth::suspend() | |
939 | ||
940 | waitFor(unsigned int, bool) | |
941 | Full name: Wait11::waitFor(unsigned int, bool) | |
942 | Source: waitfor.cc | |
943 | Used By: | |
944 | timedwait.cc: IPC::timedWait() | |
945 | contactpeer.cc: Stealth::contactPeer() | |
946 | ||
947 | waitForRequest() | |
948 | Full name: Stealth::waitForRequest() | |
949 | Source: waitforrequest.cc | |
950 | Used By: | |
951 | processrequests.cc: Stealth::processRequests() | |
943 | report1.cc: Report::Report(Options&, PolicyFile const&) | |
944 | ||
945 | waitForKey() | |
946 | Full name: Stealth::waitForKey() | |
947 | Source: waitforkey.cc | |
948 | Used By: | |
949 | jobshandler.cc: Stealth::jobsHandler() | |
952 | 950 | |
953 | 951 | waitForSentinel(FBB::Process&) |
954 | 952 | Full name: IntegrityScanner::waitForSentinel(FBB::Process&) |
958 | 956 | put.cc: IntegrityScanner::put(std::string const&) |
959 | 957 | startcommandshells.cc: IntegrityScanner::startCommandShells() |
960 | 958 | |
961 | waitSignal(bool) | |
962 | Full name: Wait11::waitSignal(bool) | |
963 | Source: waitsignal.cc | |
964 | Used By: | |
965 | timedwait.cc: IPC::timedWait() | |
966 | wait.cc: IPC::wait(bool) | |
967 | ||
968 | 959 | write(std::string const&) |
969 | 960 | Full name: IntegrityScanner::write(std::string const&) |
970 | 961 | Source: write.cc |
971 | 962 | Used By: |
972 | 963 | put.cc: IntegrityScanner::put(std::string const&) |
973 | 964 | |
974 | write(std::string const&) const | |
975 | Full name: IPC::write(std::string const&) const | |
976 | Source: write.cc | |
977 | Used By: | |
978 | sendrequestor.cc: IPC::sendRequestor(std::string const&) | |
979 | signaldaemon.cc: IPC::signalDaemon() | |
980 | ||
981 | writeRunFile(int) | |
982 | Full name: IPC::writeRunFile(int) | |
983 | Source: writerunfile.cc | |
984 | Used By: | |
985 | parentprocess.cc: Stealth::parentProcess() | |
986 | ||
987 | 965 | years |
988 | 966 | Full name: Icmbuild::years |
989 | 967 | Source: version.cc |
0 | #include "stealthenums.ih" | |
1 | ||
2 | ostream &StealthEnums::leave(ostream &out) | |
3 | { | |
4 | out << endl; | |
5 | throw LEAVE; | |
6 | } |
6 | 6 | { |
7 | 7 | enum Mode // uses bit-flags values |
8 | 8 | { |
9 | LEAVE = 1 << 0, | |
10 | ||
11 | 9 | INTEGRITY_SCAN = 1 << 1, // perform an integrity scan |
12 | ||
13 | WAIT = 1 << 3, // waiting for another signal/tine | |
14 | 10 | |
15 | 11 | RERUN = 1 << 4, // rerun on request at WAITING |
16 | 12 | |
20 | 16 | |
21 | 17 | RELOAD = 1 << 6, // reload the config files |
22 | 18 | |
23 | TERMINATE = 1 << 7, // terminate a Stealth run (-> SIGTERM, | |
24 | // SIGINT) | |
19 | TERMINATE = 1 << 7, // terminate a Stealth run | |
25 | 20 | |
26 | 21 | UNKNOWN = 1 << 8, |
27 | 22 | }; |
28 | ||
29 | static std::ostream &leave(std::ostream &out); | |
30 | 23 | }; |
31 | 24 | |
32 | 25 | inline constexpr StealthEnums::Mode operator|( |
37 | 30 | ); |
38 | 31 | } |
39 | 32 | |
40 | ||
41 | 33 | #endif |
0 | /* | |
1 | demo.cc | |
2 | ||
3 | g++ demo.cc -L../.. -lstealth | & less | |
4 | */ | |
5 | ||
6 | #include "demo.h" | |
7 | ||
8 | int main(int argc, char **argv, char **envp) | |
9 | { | |
10 | try | |
11 | { | |
12 | Reporter rep("report"); | |
13 | ||
14 | rep << Util::date << ": Hello world\n"; | |
15 | ||
16 | rep.reset(); | |
17 | ||
18 | string s; | |
19 | ||
20 | cout << "========= 0 ===========\n"; | |
21 | ||
22 | while (getline(rep, s)) | |
23 | cout << "Added: " << s << "\n"; | |
24 | ||
25 | cout << "========= 1 ===========\n"; | |
26 | ||
27 | sleep(5); | |
28 | ||
29 | rep.reinit(); // make sure we can add new info | |
30 | // as a new run | |
31 | ||
32 | // insert info | |
33 | rep << Util::date << ": Hello world (2nd time)\n"; | |
34 | ||
35 | rep.reset(); // reset the stream to read it again | |
36 | ||
37 | while (getline(rep, s)) | |
38 | cout << "Added: " << s << "\n"; | |
39 | ||
40 | cout << "========= 2 ===========\n"; | |
41 | ||
42 | return 0; | |
43 | } | |
44 | catch(exception const &e) | |
45 | { | |
46 | cerr << "Exception " << e.what() << "\n"; | |
47 | return 1; | |
48 | } | |
49 | } |
0 | // demo.h | |
1 | ||
2 | #ifndef _H_demo_ | |
3 | #define _H_demo_ | |
4 | ||
5 | /* | |
6 | $Id$ | |
7 | ||
8 | $Log$ | |
9 | Revision 1.3 2003/11/30 14:21:29 frank | |
10 | Adding facilities to reuse the Reporter: reinit() re-initializes the reporter | |
11 | but note that reset() must still be used. See demo/demo.cc for an example | |
12 | ||
13 | Revision 1.2 2003/06/20 18:58:14 frank | |
14 | Changes are recorded in stealth/debian/changelog | |
15 | ||
16 | */ | |
17 | ||
18 | //#include <iosfwd> | |
19 | #include <iostream> | |
20 | //#include <fstream> | |
21 | #include <string> | |
22 | //#include <sstream> | |
23 | ||
24 | #include "../reporter.h" | |
25 | #include "../../util/util.h" | |
26 | #include "../../errno/errno.h" | |
27 | ||
28 | using namespace FBB; | |
29 | using namespace std; | |
30 | ||
31 | #endif |
0 | #include "stealthlog.ih" | |
1 | ||
2 | bool StealthLog::hasMail() | |
3 | { | |
4 | return d_stealthlog.seekp(0, ios::end).tellp() > d_beginMail; | |
5 | } | |
6 |
0 | #include "stealthlog.ih" | |
1 | ||
2 | string const &StealthLog::headerLine() const | |
3 | { | |
4 | return d_headerLine; | |
5 | } |
0 | #include "stealthlog.ih" | |
1 | ||
2 | void StealthLog::open(string const &name) | |
3 | { | |
4 | d_name = name; | |
5 | d_stealthlog.open(name, ios::out | ios::ate | ios::in); | |
6 | ||
7 | if (not d_stealthlog) | |
8 | { | |
9 | d_stealthlog.clear(); | |
10 | Exception::open(d_stealthlog, name, ios::out | ios::in | ios::trunc); | |
11 | } | |
12 | ||
13 | ostringstream headerTxt; | |
14 | headerTxt << "\n" | |
15 | "STEALTH (" << Icmbuild::version << ") started at " << | |
16 | Options::instance().rfc2822() << '\n'; | |
17 | ||
18 | d_headerLine = headerTxt.str(); | |
19 | ||
20 | d_stealthlog << d_headerLine << endl; | |
21 | ||
22 | rdbuf(d_stealthlog.rdbuf()); | |
23 | } |
0 | #include "stealthlog.ih" | |
1 | ||
2 | void StealthLog::refresh() | |
3 | { | |
4 | d_stealthlog.clear(); | |
5 | ||
6 | d_startSize = d_stealthlog.seekp(0, ios::end).tellp(); | |
7 | ||
8 | d_beginMail = d_startSize; | |
9 | } | |
10 | ||
11 | ||
12 | ||
13 | ||
14 | ||
15 | ||
16 |
0 | #include "stealthlog.ih" | |
1 | ||
2 | void StealthLog::rewind() | |
3 | { | |
4 | d_stealthlog.seekg(d_startSize).tellg(); | |
5 | } | |
6 |
0 | #include "stealthlog.ih" | |
1 | ||
2 | void StealthLog::scanHeader() | |
3 | { | |
4 | d_startSize = d_stealthlog.seekp(0, ios::end).tellp(); | |
5 | ||
6 | *this << "STEALTH integrity scan at " << | |
7 | Options::instance().rfc2822() << endl; | |
8 | ||
9 | d_beginMail = d_stealthlog.tellp(); | |
10 | } | |
11 | ||
12 | ||
13 | ||
14 | ||
15 | ||
16 | ||
17 |
0 | #ifndef STEALTHLOG_H_ | |
1 | #define STEALTHLOG_H_ | |
2 | ||
3 | #include <string> | |
4 | #include <fstream> | |
5 | ||
6 | class StealthLog: public std::ostream | |
7 | { | |
8 | std::ios::pos_type d_startSize = 0; | |
9 | std::ios::pos_type d_beginMail = 0; | |
10 | ||
11 | std::fstream d_stealthlog; | |
12 | std::string d_name; | |
13 | std::string d_headerLine; | |
14 | ||
15 | public: | |
16 | StealthLog() = default; | |
17 | ||
18 | StealthLog(StealthLog const &other) = delete; | |
19 | StealthLog &operator=(StealthLog const &other) = delete; | |
20 | ||
21 | void refresh(); // set d_beginMail to the log's EOF pos. | |
22 | void scanHeader(); // writes the integrity scan header, | |
23 | // initializes d_beginMail | |
24 | ||
25 | std::string const &headerLine() const; // returns info about the | |
26 | // starting date/time of this stealth run | |
27 | ||
28 | std::istream &in(); | |
29 | bool hasMail(); // true if there is info beyond d_beginMail | |
30 | ||
31 | void open(std::string const &name); | |
32 | void close(); | |
33 | ||
34 | void rewind(); // prepare for reading | |
35 | }; | |
36 | ||
37 | inline std::istream &StealthLog::in() | |
38 | { | |
39 | return d_stealthlog; | |
40 | } | |
41 | ||
42 | inline void StealthLog::close() | |
43 | { | |
44 | d_stealthlog.close(); | |
45 | } | |
46 | ||
47 | #endif |
0 | #include "stealthlog.h" | |
1 | ||
2 | #include <iostream> | |
3 | #include <sstream> | |
4 | ||
5 | #include <bobcat/exception> | |
6 | #include <bobcat/mstream> | |
7 | ||
8 | #include "../options/options.h" | |
9 | ||
10 | namespace Icmbuild | |
11 | { | |
12 | extern char const version[]; | |
13 | } | |
14 | ||
15 | using namespace FBB; | |
16 | using namespace std; |
0 | //#include "stealthlog.ih" | |
1 | // | |
2 | //int StealthLog::sync() | |
3 | //{ | |
4 | // return MultiStreambuf::pSync(); | |
5 | //} |
0 | #ifndef INCLUDED_SYSLOGSTRUCT_ | |
1 | #define INCLUDED_SYSLOGSTRUCT_ | |
2 | ||
3 | #include <string> | |
4 | #include <bobcat/syslogstream> | |
5 | ||
6 | struct SyslogStruct | |
7 | { | |
8 | bool requested; | |
9 | FBB::Priority priority; | |
10 | FBB::Facility facility; | |
11 | std::string tag; | |
12 | ||
13 | SyslogStruct(); | |
14 | }; | |
15 | ||
16 | inline SyslogStruct::SyslogStruct() | |
17 | : | |
18 | requested(false) | |
19 | {} | |
20 | ||
21 | #endif |
0 | #include "util.ih" | |
1 | ||
2 | void Util::absPath(string const &base, string &fileName) | |
3 | { | |
4 | if (fileName.front() != '/') | |
5 | fileName = realPath(base + fileName); | |
6 | } |
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 | //} |
1 | 1 | |
2 | 2 | string Util::realPath(string const &path) |
3 | 3 | { |
4 | char *cp = ::realpath(path.c_str(), 0); | |
5 | string ret = cp; | |
6 | free(cp); | |
4 | String::Type type; | |
5 | vector<string> component = String::split(&type, path, "/"); | |
6 | ||
7 | if (type != String::NORMAL) | |
8 | throw Exception() << "Filename `" << path << "': not supported"; | |
9 | ||
10 | component.resize( | |
11 | remove(component.begin(), component.end(), ".") | |
12 | - | |
13 | component.begin() | |
14 | ); | |
15 | ||
16 | while (true) | |
17 | { | |
18 | size_t from = find(component.begin(), component.end(), "..") | |
19 | - component.begin(); | |
20 | ||
21 | if (from == component.size()) // at the last entry: done | |
22 | break; | |
23 | ||
24 | size_t to = find_if(component.begin() + from + 1, component.end(), | |
25 | [&](string const &element) | |
26 | { | |
27 | return element != ".."; | |
28 | } | |
29 | ) - component.begin(); | |
30 | ||
31 | ||
32 | size_t count = to - from; // # ".." entries | |
33 | ||
34 | size_t firstErase = from >= count ? // first to erase | |
35 | from - count | |
36 | : | |
37 | 0; | |
38 | ||
39 | component.erase(component.begin() + firstErase, | |
40 | component.begin() + to); | |
41 | } | |
42 | ||
43 | string ret(1, '/'); | |
44 | ||
45 | for(auto &str: component) | |
46 | ret += str + '/'; | |
47 | ||
48 | ret.pop_back(); | |
49 | ||
7 | 50 | return ret; |
8 | 51 | } |
8 | 8 | static bool mkdir(std::string const &path); // pathname to a file |
9 | 9 | // find full path name |
10 | 10 | static std::string realPath(std::string const &path); |
11 | static void absPath(std::string const &path, std::string &fileName); | |
11 | 12 | }; |
12 | 13 | |
13 | 14 | #endif |
0 | 0 | #include "util.h" |
1 | 1 | |
2 | #include <ostream> | |
3 | 2 | #include <string> |
4 | #include <climits> | |
5 | #include <cstdlib> | |
3 | #include <algorithm> | |
4 | ||
5 | // ::mkdir | |
6 | 6 | #include <libgen.h> |
7 | #include <sys/stat.h> | |
7 | 8 | |
8 | #include <sys/stat.h> | |
9 | #include <sys/types.h> | |
9 | #include <bobcat/string> | |
10 | #include <bobcat/exception> | |
10 | 11 | |
11 | 12 | using namespace std; |
13 | using namespace FBB; |
0 | #include "wait11.ih" | |
1 | ||
2 | void Wait11::notify() | |
3 | { | |
4 | lock_guard<mutex> lock(d_mutex); | |
5 | d_signaled = true; | |
6 | d_condition.notify_one(); | |
7 | } |
0 | #ifndef INCLUDED_WAIT11_ | |
1 | #define INCLUDED_WAIT11_ | |
2 | ||
3 | #include <mutex> | |
4 | #include <condition_variable> | |
5 | ||
6 | class Wait11 | |
7 | { | |
8 | bool d_signaled = false; | |
9 | std::mutex d_mutex; | |
10 | std::condition_variable d_condition; | |
11 | ||
12 | public: | |
13 | void waitSignal(bool doM2 = true); // wait for a signal to arrive | |
14 | void waitFor(size_t seconds, bool doM2 = true); | |
15 | ||
16 | void notify(); | |
17 | ||
18 | bool signaled() const; | |
19 | ||
20 | private: | |
21 | }; | |
22 | ||
23 | inline bool Wait11::signaled() const | |
24 | { | |
25 | return d_signaled; | |
26 | } | |
27 | ||
28 | #endif |
0 | #include "wait11.ih" | |
1 | ||
2 | void Wait11::waitFor(size_t seconds, bool doM2) | |
3 | { | |
4 | d_signaled = false; | |
5 | ||
6 | while (true) | |
7 | { | |
8 | unique_lock<mutex> lock(d_mutex); // get the lock | |
9 | ||
10 | if (d_condition.wait_for(lock, chrono::seconds(seconds)) == | |
11 | std::cv_status::timeout) | |
12 | { | |
13 | if (doM2) | |
14 | m2 << "timeout after " << seconds << " seconds" << endl; | |
15 | return; | |
16 | } | |
17 | ||
18 | if (d_signaled) | |
19 | { | |
20 | if (doM2) | |
21 | m2 << "received signal: done waiting" << endl; | |
22 | return; | |
23 | } | |
24 | } | |
25 | } |