├── .gitignore ├── stealth ├── stealth │ ├── mailreport.cc │ ├── frame │ ├── icmconf │ ├── parentprocess.cc │ ├── pingrequest.cc │ ├── terminate.cc │ ├── logreportbuf1.cc │ ├── terminaterequest.cc │ ├── acceptmode.cc │ ├── sync.cc │ ├── overflow.cc │ ├── suspend.cc │ ├── destructor.cc │ ├── rerun.cc │ ├── rerunrequest.cc │ ├── resume.cc │ ├── setupfatalreport.cc │ ├── waitforkey.cc │ ├── resumerequest.cc │ ├── notifytask.cc │ ├── reloadrequest.cc │ ├── stealth1.cc │ ├── unknownrequest.cc │ ├── deniedmode.cc │ ├── policymode.cc │ ├── autoscan.cc │ ├── suspendrequest.cc │ ├── integrityscan.cc │ ├── childprocess.cc │ ├── dotasks.cc │ ├── setuniqueptrs.cc │ ├── incomingrequest.cc │ ├── ipcmode.cc │ ├── jobshandler.cc │ ├── reload.cc │ ├── data.cc │ ├── stealth.ih │ ├── nextjob.cc │ ├── ipcinterface.cc │ └── stealth.h ├── TODO ├── frame ├── msg │ ├── frame │ ├── icmconf │ ├── driver │ │ ├── build │ │ └── driver.cc │ ├── msg1.cc │ ├── msg2.cc │ ├── msg.ih │ ├── data.cc │ ├── msg.h │ └── setverbosity.cc ├── logunit │ ├── frame │ ├── icmconf │ ├── logunit1.cc │ ├── setuplogs2.cc │ ├── logunit.ih │ ├── newlog.cc │ ├── newsyslogstream.cc │ ├── logunit.h │ └── setuplogs1.cc ├── options │ ├── frame │ ├── icmconf │ ├── setpolicypath.cc │ ├── randomaddition.cc │ ├── setmail.cc │ ├── getcwd.cc │ ├── setstdout.cc │ ├── foregroundonly.cc │ ├── rfc2822.cc │ ├── setlog.cc │ ├── setparsepolicy.cc │ ├── setverbosity.cc │ ├── setconfigoptions.cc │ ├── requiresomeargument.cc │ ├── options.ih │ ├── setskipfile.cc │ ├── setsyslog.cc │ ├── setrandomdelay.cc │ ├── settimestamp.cc │ ├── setsyslogfacility.cc │ ├── setrepeat.cc │ ├── setsyslogpriority.cc │ ├── checkm.cc │ ├── setcommandnr.cc │ ├── checkmode.cc │ ├── setmode.cc │ ├── setdownloadsize.cc │ ├── data.cc │ ├── options1.cc │ └── oldoptions.cc ├── runmode │ ├── frame │ ├── icmconf │ ├── runmode.ih │ ├── setmode.cc │ ├── data.cc │ └── runmode.h ├── report │ ├── frame │ ├── icmconf │ ├── destructor.cc │ ├── hasmail.cc │ ├── rewind.cc │ ├── demo │ │ ├── demo.h │ │ └── demo.cc │ ├── mail.cc │ ├── refresh.cc │ ├── scanheader.cc │ ├── timestamp.cc │ ├── processmail.cc │ ├── report.ih │ ├── report1.cc │ ├── sendmail.cc │ └── report.h ├── stealthenums │ ├── frame │ ├── icmconf │ ├── stealthenums.ih │ └── stealthenums.h ├── util │ ├── icmconf │ ├── abspath.cc │ ├── util.ih │ ├── util.h │ ├── mkdir.cc │ └── realpath.cc ├── VERSION.h ├── policyfile │ ├── frame │ ├── icmconf │ ├── policyfile1.cc │ ├── chdirbase.cc │ ├── load.cc │ ├── policyfile.ih │ ├── insert.cc │ ├── loadoptions.cc │ ├── fixrelativelocations.cc │ ├── directivesandcommands.cc │ ├── fetchcommands.cc │ ├── replacedefines.cc │ ├── data.cc │ └── policyfile.h ├── integrityscanner │ ├── frame │ ├── icmconf │ ├── killchildren.cc │ ├── setsentinel.cc │ ├── doplaincommand.cc │ ├── datetime.cc │ ├── data.cc │ ├── filename.cc │ ├── remote.cc │ ├── removefirstword.cc │ ├── addto.cc │ ├── replace.cc │ ├── loadskipfiles.cc │ ├── skip.cc │ ├── waitforsentinel.cc │ ├── setskip.cc │ ├── getpath.cc │ ├── putcommand.cc │ ├── foreground.cc │ ├── nextcommand.cc │ ├── integrityscanner.ih │ ├── testexitvalue.cc │ ├── checksize.cc │ ├── write.cc │ ├── docheckcommand.cc │ ├── removelog.cc │ ├── execute.cc │ ├── startcommandshells.cc │ ├── skipdecision.cc │ ├── local.cc │ ├── copy.cc │ ├── run.cc │ ├── sameoutput.cc │ ├── get.cc │ ├── read.cc │ ├── integrityscanner1.cc │ └── put.cc ├── documentation │ ├── manual │ │ ├── install │ │ │ ├── intro.yo │ │ │ └── compile.yo │ │ ├── running │ │ │ ├── policy.yo │ │ │ ├── obtaining.yo │ │ │ ├── checkingsetuid.yo │ │ │ ├── checkingconfig.yo │ │ │ ├── installing.yo │ │ │ ├── intro.yo │ │ │ ├── define.yo │ │ │ ├── mailed.yo │ │ │ ├── checkingfind.yo │ │ │ ├── newrunsame.yo │ │ │ ├── logrotate.yo │ │ │ ├── rsyslog.yo │ │ │ ├── checking.yo │ │ │ ├── failing.yo │ │ │ ├── use.yo │ │ │ ├── policy.demo │ │ │ ├── commands.yo │ │ │ ├── makepolicy.yo │ │ │ ├── cron.yo │ │ │ ├── skipping.yo │ │ │ ├── status.yo │ │ │ ├── firstrun.yo │ │ │ ├── rotate.yo │ │ │ └── files.yo │ │ ├── access │ │ │ ├── intro.yo │ │ │ ├── using.yo │ │ │ ├── client.yo │ │ │ ├── login.yo │ │ │ └── monitor.yo │ │ ├── policy │ │ │ ├── commands.yo │ │ │ ├── label.yo │ │ │ ├── defines.yo │ │ │ └── intro.yo │ │ ├── usage.yo │ │ ├── usage.cc │ │ ├── stealth.sty │ │ └── kickstart.yo │ ├── images │ │ ├── nextjob.jpg │ │ ├── communication.jpg │ │ ├── ipcinterface.jpg │ │ └── molds │ │ │ ├── comflow.odp │ │ │ ├── figure.odp │ │ │ ├── nextjob.obp │ │ │ ├── ipcinterface.odp │ │ │ ├── communication.odp │ │ │ ├── 2jpg │ │ │ └── README │ └── example-policies │ │ ├── simple.pol │ │ └── localhost.pol ├── VERSION ├── share │ ├── etc │ │ ├── stealth │ │ │ └── cleanup.rc │ │ └── logrotate.d │ │ │ └── target │ └── usr │ │ └── bin │ │ ├── stealthmail │ │ ├── stealthcron │ │ └── stealthcleanup ├── version.cc ├── icmake │ ├── backtick │ ├── cuteoln │ ├── logfile │ ├── destinstall │ ├── github │ ├── run │ ├── setopt │ ├── special │ ├── manpage │ ├── clean │ ├── installer │ ├── uninstall │ ├── log │ ├── pathfile │ ├── md │ ├── findall │ ├── remove │ ├── precompileheaders │ ├── loginstall │ ├── logzip │ └── manual ├── main.ih ├── syslogstruct │ └── syslogstruct.h ├── CLASSES ├── ACKNOWLEDGEMENTS ├── icmconf ├── required ├── README.4.00.00 ├── icmconf2 ├── INSTALL.im ├── README.messages ├── README.3.00.00 ├── CHANGELOG ├── README.class-setup ├── README └── main.cc ├── excluded ├── README └── sourcetar /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stealth/stealth/mailreport.cc: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /stealth/TODO: -------------------------------------------------------------------------------- 1 | --all done-- 2 | 3 | -------------------------------------------------------------------------------- /stealth/frame: -------------------------------------------------------------------------------- 1 | #include "main.ih" 2 | -------------------------------------------------------------------------------- /excluded: -------------------------------------------------------------------------------- 1 | test 2 | documentation/images/molds 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /stealth/msg/frame: -------------------------------------------------------------------------------- 1 | #include "msg.ih" 2 | 3 | Msg:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/logunit/frame: -------------------------------------------------------------------------------- 1 | #include "logunit.ih" 2 | 3 | LogUnit:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/options/frame: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | Options:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/runmode/frame: -------------------------------------------------------------------------------- 1 | #include "runmode.ih" 2 | 3 | RunMode:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/report/frame: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/stealth/frame: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/msg/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "msg" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/stealthenums/frame: -------------------------------------------------------------------------------- 1 | #include "stealthenums.ih" 2 | 3 | StealthEnums:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/util/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "util" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/VERSION.h: -------------------------------------------------------------------------------- 1 | #include "VERSION" 2 | SUBST(_CurVers_)(VERSION) 3 | SUBST(_CurYrs_)(YEARS) 4 | -------------------------------------------------------------------------------- /stealth/logunit/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "logunit" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/options/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "options" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/policyfile/frame: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile:: 4 | { 5 | } 6 | 7 | -------------------------------------------------------------------------------- /stealth/report/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "report" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/runmode/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "runmode" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/stealth/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "stealth" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/msg/driver/build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | g++ --std=c++11 driver.cc -L../tmp/ -lmsg -lbobcat 4 | -------------------------------------------------------------------------------- /stealth/policyfile/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "policyfile" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/integrityscanner/frame: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | IntegrityScanner:: 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /stealth/msg/msg1.cc: -------------------------------------------------------------------------------- 1 | #include "msg.ih" 2 | 3 | Msg::Msg() 4 | : 5 | ostream(imsg.rdbuf()) 6 | {} 7 | -------------------------------------------------------------------------------- /stealth/stealthenums/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "stealthenums" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/runmode/runmode.ih: -------------------------------------------------------------------------------- 1 | #include "runmode.h" 2 | 3 | using namespace std; 4 | using namespace FBB; 5 | 6 | -------------------------------------------------------------------------------- /stealth/stealth/parentprocess.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::parentProcess() 4 | {} 5 | 6 | -------------------------------------------------------------------------------- /stealth/documentation/manual/install/intro.yo: -------------------------------------------------------------------------------- 1 | This chapter describes s()'s compilation and installation. 2 | 3 | -------------------------------------------------------------------------------- /stealth/integrityscanner/icmconf: -------------------------------------------------------------------------------- 1 | #define LIBRARY "integrityscanner" 2 | 3 | #include "../icmconf2" 4 | -------------------------------------------------------------------------------- /stealth/msg/msg2.cc: -------------------------------------------------------------------------------- 1 | #include "msg.ih" 2 | 3 | Msg::Msg(ostream &out) 4 | : 5 | ostream(out.rdbuf()) 6 | {} 7 | -------------------------------------------------------------------------------- /stealth/documentation/images/nextjob.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/nextjob.jpg -------------------------------------------------------------------------------- /stealth/stealth/pingrequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::pingRequest() 4 | { 5 | return "nop"; 6 | } 7 | -------------------------------------------------------------------------------- /stealth/stealthenums/stealthenums.ih: -------------------------------------------------------------------------------- 1 | #include "stealthenums.h" 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | -------------------------------------------------------------------------------- /stealth/VERSION: -------------------------------------------------------------------------------- 1 | #define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)"; 2 | #define VERSION "4.01.10" 3 | #define YEARS "2005-2018" 4 | -------------------------------------------------------------------------------- /stealth/logunit/logunit1.cc: -------------------------------------------------------------------------------- 1 | #include "logunit.ih" 2 | 3 | LogUnit::LogUnit(Options &options) 4 | : 5 | d_options(options) 6 | {} 7 | -------------------------------------------------------------------------------- /stealth/stealth/terminate.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::terminate() 4 | { 5 | timestamp("terminates"); 6 | } 7 | -------------------------------------------------------------------------------- /stealth/documentation/images/communication.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/communication.jpg -------------------------------------------------------------------------------- /stealth/documentation/images/ipcinterface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/ipcinterface.jpg -------------------------------------------------------------------------------- /stealth/documentation/images/molds/comflow.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/molds/comflow.odp -------------------------------------------------------------------------------- /stealth/documentation/images/molds/figure.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/molds/figure.odp -------------------------------------------------------------------------------- /stealth/documentation/images/molds/nextjob.obp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/molds/nextjob.obp -------------------------------------------------------------------------------- /stealth/report/destructor.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | Report::~Report() 4 | { 5 | if (hasMail()) 6 | processMail(); 7 | } 8 | -------------------------------------------------------------------------------- /stealth/report/hasmail.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | bool Report::hasMail() 4 | { 5 | return d_beginMail < endpos(); 6 | } 7 | 8 | -------------------------------------------------------------------------------- /stealth/runmode/setmode.cc: -------------------------------------------------------------------------------- 1 | #include "runmode.ih" 2 | 3 | void RunMode::setMode(Mode mode) 4 | { 5 | d_mode = mode; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/policy.yo: -------------------------------------------------------------------------------- 1 | Here is the complete policy file we've constructed so far: 2 | 3 | verbinclude(policy.demo) 4 | -------------------------------------------------------------------------------- /stealth/stealth/logreportbuf1.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | LogReportbuf::LogReportbuf(Report &report) 4 | : 5 | d_report(report) 6 | {} 7 | -------------------------------------------------------------------------------- /stealth/documentation/images/molds/ipcinterface.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/molds/ipcinterface.odp -------------------------------------------------------------------------------- /stealth/report/rewind.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::rewind() 4 | { 5 | clear(); 6 | seekg(d_startSize).tellg(); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /stealth/documentation/images/molds/communication.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbb-git/stealth/HEAD/stealth/documentation/images/molds/communication.odp -------------------------------------------------------------------------------- /stealth/msg/msg.ih: -------------------------------------------------------------------------------- 1 | #include "msg.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace FBB; 8 | 9 | -------------------------------------------------------------------------------- /stealth/stealth/terminaterequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::terminateRequest() 4 | { 5 | return acceptMode(TERMINATE); 6 | } 7 | -------------------------------------------------------------------------------- /stealth/stealth/acceptmode.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::acceptMode(Mode mode) 4 | { 5 | d_task.setMode(mode); 6 | return ""; 7 | } 8 | -------------------------------------------------------------------------------- /stealth/share/etc/stealth/cleanup.rc: -------------------------------------------------------------------------------- 1 | directories=" 2 | /var/stealth/target/local 3 | /var/stealth/target/remote 4 | " 5 | 6 | rmdays=30 7 | gzdays=3 8 | -------------------------------------------------------------------------------- /stealth/stealth/sync.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | int LogReportbuf::sync() 4 | { 5 | d_report.flush(); 6 | d_report.mail(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /stealth/logunit/setuplogs2.cc: -------------------------------------------------------------------------------- 1 | #include "logunit.ih" 2 | 3 | void LogUnit::setupLogs(ostream &report) 4 | { 5 | setupLogs(); 6 | d_fmsgbuf->insert(report); 7 | } 8 | -------------------------------------------------------------------------------- /stealth/report/demo/demo.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../stealthreport.h" 5 | #include "../../util/util.h" 6 | 7 | using namespace std; 8 | -------------------------------------------------------------------------------- /stealth/stealth/overflow.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | int LogReportbuf::overflow(int ch) 4 | { 5 | if (ch != EOF) 6 | d_report.put(ch); 7 | return ch; 8 | } 9 | -------------------------------------------------------------------------------- /stealth/version.cc: -------------------------------------------------------------------------------- 1 | #include "VERSION" 2 | 3 | namespace Icmbuild 4 | { 5 | char author[] = AUTHOR; 6 | char version[] = VERSION; 7 | char years[] = YEARS; 8 | } 9 | -------------------------------------------------------------------------------- /stealth/icmake/backtick: -------------------------------------------------------------------------------- 1 | list backtick(string arg) 2 | { 3 | list ret; 4 | 5 | echo(OFF); 6 | ret = `arg`; 7 | echo(g_echo); 8 | return ret; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /stealth/integrityscanner/killchildren.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::killChildren() 4 | { 5 | d_sshFork.stop(); 6 | d_shFork.stop(); 7 | } 8 | -------------------------------------------------------------------------------- /stealth/stealth/suspend.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::suspend() 4 | { 5 | m2 << "received SUSPEND request" << endl; 6 | 7 | timestamp("is suspended"); 8 | } 9 | -------------------------------------------------------------------------------- /stealth/policyfile/policyfile1.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | PolicyFile::PolicyFile(Options &options) 4 | : 5 | d_options(options) 6 | { 7 | load(); 8 | } 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /stealth/share/usr/bin/stealthmail: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | grep 'STEALTH\|MODIFIED\|ADDED\|REMOVED\|SKIPPING' | sort | uniq | 4 | /usr/bin/mail -s "$2" $3 5 | -------------------------------------------------------------------------------- /stealth/report/mail.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::mail() 4 | { 5 | if (hasMail()) 6 | processMail(); 7 | else 8 | m3 << "No new logs to mail" << endl; 9 | } 10 | -------------------------------------------------------------------------------- /stealth/util/abspath.cc: -------------------------------------------------------------------------------- 1 | #include "util.ih" 2 | 3 | void Util::absPath(string const &base, string &fileName) 4 | { 5 | if (fileName.front() != '/') 6 | fileName = realPath(base + fileName); 7 | } 8 | -------------------------------------------------------------------------------- /stealth/icmake/cuteoln: -------------------------------------------------------------------------------- 1 | string cutEoln(string text) 2 | { 3 | int len; 4 | 5 | len = strlen(text) - 1; 6 | if (text[len] == "\n") 7 | text = substr(text, 0, len); 8 | return text; 9 | } 10 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/obtaining.yo: -------------------------------------------------------------------------------- 1 | To copy the client's tt(sha1sum) program to a local directory we specify: 2 | verb( 3 | GET /usr/bin/sha1sum /root/tmp) 4 | This command must succeed. 5 | 6 | -------------------------------------------------------------------------------- /stealth/icmake/logfile: -------------------------------------------------------------------------------- 1 | void logFile(string srcdir, string src, string destdir, string dest) 2 | { 3 | chdir(g_cwd); 4 | md(destdir); 5 | 6 | run("cp " + srcdir + "/" + src + " " + destdir + "/" + dest); 7 | } 8 | -------------------------------------------------------------------------------- /stealth/documentation/images/molds/2jpg: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | convert -trim $1.pdf ../$1.jpg 4 | 5 | rm $1.pdf 6 | 7 | if [ -e ../$1-0.jpg ] 8 | then 9 | mv ../$1-0.jpg ../$1.jpg 10 | rm ../$1-1.jpg 11 | fi 12 | -------------------------------------------------------------------------------- /stealth/msg/data.cc: -------------------------------------------------------------------------------- 1 | #include "msg.ih" 2 | 3 | Msg m1; // mode report and policy commands 4 | Msg m2; // ipc related 5 | Msg m3; // informative messages (integrity scan) 6 | 7 | Msg mp(cout); 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /stealth/integrityscanner/setsentinel.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::setSentinel() 4 | { 5 | ostringstream oss; 6 | 7 | oss << "EOC " << DateTime(); 8 | d_sentinel = oss.str(); 9 | } 10 | -------------------------------------------------------------------------------- /stealth/report/refresh.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::refresh() 4 | { 5 | clear(); 6 | 7 | d_startSize = endpos(); 8 | 9 | d_beginMail = d_startSize; 10 | } 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /stealth/icmake/destinstall: -------------------------------------------------------------------------------- 1 | void destInstall(string dest, string base) 2 | { 3 | chdir(g_cwd + base); // go to the base directory 4 | run(g_cwd + "icmake/installer " + dest + "/ "); // install the files 5 | } 6 | -------------------------------------------------------------------------------- /stealth/options/setpolicypath.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setPolicyPath() 4 | { 5 | if (d_ipc) 6 | return; 7 | 8 | d_policyPath = d_arg[0]; 9 | 10 | Util::absPath(d_base, d_policyPath); 11 | } 12 | -------------------------------------------------------------------------------- /stealth/stealth/destructor.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | Stealth::~Stealth() 4 | { 5 | if (d_options.daemon()) 6 | unlink(d_options.unixDomainSocket().c_str()); 7 | 8 | delete d_logReportbuf; 9 | } 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /stealth/icmake/github: -------------------------------------------------------------------------------- 1 | void github() 2 | { 3 | run("cp -r release.yo tmp/manhtml/stealthman.html " 4 | "tmp/manual/pdf/stealth.pdf tmp/manual/html ../../wip"); 5 | run("cp changelog ../../wip/changelog.txt"); 6 | 7 | exit(0); 8 | } 9 | -------------------------------------------------------------------------------- /stealth/documentation/images/molds/README: -------------------------------------------------------------------------------- 1 | Copy figure.odp to the intended figure name, design the new figure using 2 | loimpress, save as pdf, run '2jpg new-figure' (w/o extension). 3 | 4 | The jpg figure appears in ../ (i.e., stealth/documentation/images) 5 | 6 | -------------------------------------------------------------------------------- /stealth/options/randomaddition.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | size_t Options::randomAddition() const 4 | { 5 | return d_delayInterval ? 6 | d_delayInterval * (random() / (RAND_MAX + 1.0)) 7 | : 8 | 0; 9 | } 10 | -------------------------------------------------------------------------------- /stealth/stealth/rerun.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::rerun() 4 | { 5 | *d_report << "STEALTH explicit integrity scan rerun at " << 6 | d_options.rfc2822() << endl; 7 | autoScan("rerun"); 8 | } 9 | -------------------------------------------------------------------------------- /stealth/options/setmail.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | // by default mail is ON 4 | 5 | void Options::setMail() 6 | { 7 | d_logMail = d_arg.option(0, "log-mail"); 8 | d_sendMail = not d_arg.option(0, "no-mail"); 9 | } 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /stealth/integrityscanner/doplaincommand.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::doPlainCommand(Process &child) 4 | { 5 | nextCommand(child, s_firstWord[0]); // start the next command 6 | waitForSentinel(child); // read its output 7 | } 8 | -------------------------------------------------------------------------------- /stealth/options/getcwd.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | string Options::getCwd() 4 | { 5 | string base; 6 | 7 | if (char *buffer = getcwd(0, 0)) 8 | { 9 | (base = buffer) += '/'; 10 | free(buffer); 11 | } 12 | 13 | return base; 14 | } 15 | -------------------------------------------------------------------------------- /stealth/stealth/rerunrequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::rerunRequest() 4 | { 5 | string ret = d_task.hasMode(INTEGRITY_SCAN) ? 6 | acceptMode(RERUN) 7 | : 8 | deniedMode("--rerun"); 9 | 10 | return ret; 11 | } 12 | -------------------------------------------------------------------------------- /stealth/stealth/resume.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::resume() 4 | { 5 | *d_report << "STEALTH resumes its tasks at " << d_options.rfc2822() << 6 | endl; 7 | autoScan("resume"); 8 | } 9 | -------------------------------------------------------------------------------- /stealth/stealth/setupfatalreport.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::setupFatalReport() 4 | { 5 | delete d_logReportbuf; 6 | 7 | d_logReportbuf = new LogReportbuf(*d_report); 8 | d_logReport.rdbuf(d_logReportbuf); 9 | d_logReport.clear(); 10 | } 11 | -------------------------------------------------------------------------------- /stealth/policyfile/chdirbase.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::chdirBase() const 4 | { 5 | char const *base = d_use.find("BASE")->second.c_str(); 6 | 7 | if (chdir(base) != 0) 8 | fmsg << "Can't chdir to `" << base << '\'' << noidl; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /stealth/integrityscanner/datetime.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | string IntegrityScanner::datetime() 4 | { 5 | time_t curtime = time(0); 6 | 7 | char buffer[80]; 8 | strftime(buffer, 80, "%Y%m%d-%H%M%S", localtime(&curtime)); 9 | 10 | return buffer; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /stealth/logunit/logunit.ih: -------------------------------------------------------------------------------- 1 | #include "logunit.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../options/options.h" 10 | 11 | using namespace std; 12 | using namespace FBB; 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /stealth/options/setstdout.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setStdout() 4 | { 5 | if (d_arg.option('o') or d_ipc) 6 | { 7 | if (d_daemon) 8 | fmsg << "--stdout incompatible with --daemon" << noidl; 9 | 10 | d_stdout = true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /stealth/report/scanheader.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::scanHeader() 4 | { 5 | d_startSize = endpos(); 6 | 7 | *this << "STEALTH integrity scan at " << d_options.rfc2822() << endl; 8 | 9 | d_beginMail = tellp(); 10 | } 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /stealth/stealth/waitforkey.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::waitForKey() 4 | { 5 | cin.ignore(numeric_limits::max(), '\n'); 6 | imsg << "STEALTH (foreground) TERMINATED by user-request" << endl; 7 | d_task.setMode(TERMINATE); 8 | d_job.notify(); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /stealth/util/util.ih: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include 4 | #include 5 | 6 | // ::mkdir 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace FBB; 15 | -------------------------------------------------------------------------------- /stealth/documentation/manual/access/intro.yo: -------------------------------------------------------------------------------- 1 | Access to clients should be granted using the tt(ssh) protocol. 2 | 3 | Clients must allow the monitor to connect using tt(ssh). S() connects to its 4 | clients using ssh certificates, after the monitor's public SSH-key has been 5 | transferred to the clients. 6 | -------------------------------------------------------------------------------- /stealth/icmake/run: -------------------------------------------------------------------------------- 1 | int g_dryrun = setOpt("", "DRYRUN") != ""; 2 | 3 | void runP(int testValue, string cmd) 4 | { 5 | if (g_dryrun) 6 | printf(cmd, "\n"); 7 | else 8 | system(testValue, cmd); 9 | } 10 | 11 | void run(string cmd) 12 | { 13 | runP(0, cmd); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /stealth/options/foregroundonly.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::foregroundOnly(char const *optionName) const 4 | { 5 | if (not d_foreground) 6 | fmsg << "--" << optionName << " is only valid for a " << 7 | basename() << " foreground process" << noidl; 8 | } 9 | -------------------------------------------------------------------------------- /stealth/stealth/resumerequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | std::string Stealth::resumeRequest() 4 | { 5 | string ret = d_task.hasMode(SUSPEND) ? 6 | acceptMode(RESUME) 7 | : 8 | deniedMode("--resume"); 9 | 10 | return ret; 11 | } 12 | -------------------------------------------------------------------------------- /stealth/icmake/setopt: -------------------------------------------------------------------------------- 1 | string setOpt(string install_im, string envvar) 2 | { 3 | list optvar; 4 | string ret; 5 | 6 | optvar = getenv(envvar); 7 | 8 | if (optvar[0] == "1") 9 | ret = optvar[1]; 10 | else 11 | ret = install_im; 12 | 13 | return ret; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /stealth/options/rfc2822.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | string Options::rfc2822() const 4 | { 5 | return DateTime( 6 | d_timestamp == UTCTIMESTAMPS ? 7 | DateTime::UTC 8 | : 9 | DateTime::LOCALTIME 10 | ).rfc2822(); 11 | } 12 | -------------------------------------------------------------------------------- /stealth/stealth/notifytask.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::notifyTask() 4 | { 5 | d_task = d_pending; // set the next request 6 | d_pending.setMode(UNKNOWN); // clear the pending request 7 | 8 | d_job.notify(); // notify processRequests (i.e., 9 | } 10 | -------------------------------------------------------------------------------- /stealth/msg/driver/driver.cc: -------------------------------------------------------------------------------- 1 | #include "../msg.h" 2 | 3 | using namespace std; 4 | 5 | int main() 6 | { 7 | m1 << "m1" << endl; 8 | 9 | Msg::setVerbosity(0); 10 | m1 << "invisible" << endl; 11 | 12 | Msg::setVerbosity(1); 13 | m1 << "visible" << endl; 14 | m2 << "invisible" << endl; 15 | } 16 | -------------------------------------------------------------------------------- /stealth/integrityscanner/data.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // split the first word from the trailing word(s) 4 | Pattern IntegrityScanner::s_firstWord("(\\S+)(\\s+(.*))?"); 5 | 6 | // pick up the exit value in testExitValue() 7 | Pattern IntegrityScanner::s_exitValue("(\\d+)\\s*$"); 8 | -------------------------------------------------------------------------------- /stealth/icmake/special: -------------------------------------------------------------------------------- 1 | void special() 2 | { 3 | if (! exists("release.yo") || "VERSION" newer "release.yo") 4 | { 5 | system("touch version.cc"); 6 | run("gcc -E VERSION.h | grep -v '#' | sed 's/\\\"//g' > " 7 | "release.yo"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /stealth/documentation/manual/policy/commands.yo: -------------------------------------------------------------------------------- 1 | Following the bf(USE) specifications, em(commands) can be specified. The 2 | commands are executed in their order of appearance in the policy 3 | file. Processing continues until the last command has been processed or until 4 | a tested command (see below) returns a non-zero return value. 5 | -------------------------------------------------------------------------------- /stealth/integrityscanner/filename.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | string IntegrityScanner::fileName(string const &name) 4 | { 5 | string::size_type pos; 6 | 7 | pos = name.rfind("/"); // name contains dir-separator ? 8 | 9 | return pos == string::npos ? name : name.substr(pos + 1); 10 | } 11 | -------------------------------------------------------------------------------- /stealth/stealth/reloadrequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::reloadRequest() 4 | { 5 | string ret = d_task.hasMode(INTEGRITY_SCAN) ? 6 | acceptMode(RELOAD) 7 | : 8 | deniedMode("--reload"); 9 | return ret; 10 | } 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /stealth/stealth/stealth1.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | Stealth::Stealth() 4 | : 5 | d_logUnit(d_options), 6 | d_ipc(0), // Semaphores 7 | d_job(1), 8 | d_logReport(0) 9 | { 10 | d_task.setMode(d_options.mode()); 11 | d_pending.setMode(UNKNOWN); 12 | } 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /stealth/documentation/manual/usage.yo: -------------------------------------------------------------------------------- 1 | When s() is started without arguments, it provides some help about how 2 | to start it. A message like the following is produced: 3 | 4 | verbinclude(../../tmp/usage.txt) 5 | 6 | Note that with the second type of usage the policy file is not required: 7 | here only the tt(pidfile) must be specified. 8 | -------------------------------------------------------------------------------- /stealth/icmake/manpage: -------------------------------------------------------------------------------- 1 | #define MANPAGE "../../tmp/man/" ${PROJECT} ".1" 2 | 3 | void manpage() 4 | { 5 | md("tmp/man tmp/manhtml"); 6 | 7 | chdir("documentation/man"); 8 | 9 | run("yodl2man -o " MANPAGE " " PROJECT); 10 | run("yodl2html -o ../../tmp/manhtml/" PROJECT "man.html " PROJECT); 11 | 12 | exit(0); 13 | } 14 | -------------------------------------------------------------------------------- /stealth/stealth/unknownrequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::unknownRequest() 4 | { 5 | ostringstream msg; 6 | 7 | string ret("unknown request"); 8 | msg << "received " << ret; 9 | 10 | m2 << msg.str() << endl; 11 | *d_report << msg.str() << endl; 12 | 13 | return ret; 14 | } 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /stealth/options/setlog.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | int Options::setLog() 4 | { 5 | if 6 | ( 7 | (d_cmdLineOption & LOG) // already a command line option 8 | or 9 | not d_arg.option(&d_logName, 'L') 10 | ) 11 | return 0; 12 | 13 | Util::absPath(d_base, d_logName); 14 | return LOG; 15 | } 16 | -------------------------------------------------------------------------------- /stealth/main.ih: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "options/options.h" 7 | #include "stealth/stealth.h" 8 | 9 | namespace Icmbuild 10 | { 11 | extern char author[]; 12 | extern char version[]; 13 | extern char years[]; 14 | } 15 | 16 | using namespace std; 17 | using namespace FBB; 18 | -------------------------------------------------------------------------------- /stealth/options/setparsepolicy.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setParsePolicy() 4 | { 5 | mp.setstate(ios::failbit); 6 | if ((d_parsePolicy = d_arg.option('p'))) 7 | { 8 | foregroundOnly("--parse-policy-file"); 9 | 10 | if (d_parsePolicy > 1) // -pp shows the analysis as well 11 | mp.clear(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /stealth/icmake/clean: -------------------------------------------------------------------------------- 1 | void clean(int dist) 2 | { 3 | run("rm -rf " 4 | "build-stamp configure-stamp " 5 | "options/SKEL " 6 | "tmp/*.o tmp/usage* " + 7 | "o */o release.yo tmp/lib*.a " 8 | ); 9 | 10 | if (dist) 11 | run("rm -rf tmp *.ih.gch */*.ih.gch"); 12 | 13 | exit(0); 14 | } 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /stealth/integrityscanner/remote.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::remote(string const &cmd) 4 | { 5 | d_testExitValue = !removeFirstWord("NOTEST"); // [NOTEST] ... 6 | 7 | if (removeFirstWord("CHECK")) // ... CHECK ... 8 | doCHECKcommand(d_sshFork); 9 | else 10 | doPlainCommand(d_sshFork); 11 | } 12 | -------------------------------------------------------------------------------- /stealth/report/timestamp.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::timestamp(char const *label, size_t nScans) 4 | { 5 | static char plural[] = "s"; 6 | 7 | plural[0] = nScans != 1 ? 's' : 0; 8 | 9 | *this << "STEALTH " << label << " after " << nScans << " scan" << 10 | plural << " at " << d_options.rfc2822() << endl; 11 | mail(); 12 | } 13 | -------------------------------------------------------------------------------- /stealth/logunit/newlog.cc: -------------------------------------------------------------------------------- 1 | #include "logunit.ih" 2 | 3 | ostream *LogUnit::newLog() 4 | try 5 | { 6 | string const &name = d_options.logName(); 7 | 8 | return name.empty() ? 0 : new Log(name); 9 | } 10 | catch (exception const &exc) 11 | { 12 | fmsg << "cannot write log file `" << d_options.logName() << '\'' << noidl; 13 | return 0; // to make the compiler happy 14 | } 15 | -------------------------------------------------------------------------------- /stealth/report/processmail.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::processMail() 4 | { 5 | if (d_options.logMail()) 6 | { 7 | rewind(); 8 | 9 | string line; 10 | while (std::getline(*this, line)) 11 | imsg << "Mail: " << line << endl; 12 | } 13 | 14 | if (d_options.sendMail()) 15 | sendMail(); 16 | 17 | refresh(); 18 | } 19 | -------------------------------------------------------------------------------- /stealth/options/setverbosity.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setVerbosity() 4 | { 5 | string verbosity; 6 | 7 | d_verbosity = (d_arg.option(&verbosity, 'V')) ? 8 | stoul(verbosity) 9 | : 10 | s_defaultVerbosity; 11 | 12 | Msg::setVerbosity(d_verbosity); 13 | } 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /stealth/stealth/deniedmode.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | std::string Stealth::deniedMode(char const *request) 4 | { 5 | ostringstream ostr; 6 | 7 | ostr << "Stealth daemon (pid = " << getpid() << "): `" << request << 8 | "' not available in mode " << d_task; 9 | 10 | 11 | m2 << "ignored --rerun in mode " << d_task << endl; 12 | 13 | return ostr.str(); 14 | } 15 | -------------------------------------------------------------------------------- /stealth/documentation/manual/usage.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | #include "../../VERSION" 7 | 8 | #include "../../version.cc" 9 | #include "../../options/options.h" 10 | #include "../../options/data.cc" 11 | #include "../../options/usage.cc" 12 | 13 | int main(int argc, char **argv) 14 | { 15 | Options::usage("stealth"); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /stealth/integrityscanner/removefirstword.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | bool IntegrityScanner::removeFirstWord(char const *word) 4 | { 5 | if (s_firstWord[1] != word) 6 | return false; 7 | 8 | s_firstWord.match(s_firstWord[3]); // make sure firstword[1] now contains 9 | // the next word (of d_firstword[3]) 10 | return true; 11 | } 12 | -------------------------------------------------------------------------------- /stealth/options/setconfigoptions.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setConfigOptions() 4 | { 5 | setMail(); // sets log-mail and no-mail 6 | setSkipFile(); 7 | 8 | setLog(); 9 | setTimestamp(); 10 | 11 | setSyslog(); 12 | 13 | setVerbosity(); 14 | setStdout(); 15 | 16 | setRepeat(); 17 | setRandomDelay(); 18 | setDownloadSize(); 19 | } 20 | -------------------------------------------------------------------------------- /stealth/share/etc/logrotate.d/target: -------------------------------------------------------------------------------- 1 | /root/stealth/report /var/log/stealth/client-small.log { 2 | weekly 3 | rotate 12 4 | compress 5 | missingok 6 | copytruncate 7 | sharedscripts 8 | prerotate 9 | /usr/bin/stealth --suspend /root/stealth/small.uds 10 | endscript 11 | postrotate 12 | /usr/bin/stealth --resume /root/stealth/small.uds 13 | endscript 14 | } 15 | -------------------------------------------------------------------------------- /stealth/icmake/installer: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -eq 0 ] ; then 4 | echo destination path, ending in /, must be provided 5 | exit 0 6 | fi 7 | 8 | for src in `find -mindepth 1 -type d` # create missing target dirs 9 | do 10 | [ ! -e $1$src ] && mkdir -p $1$src 11 | done 12 | 13 | for file in `find -type f -or -type l` 14 | do 15 | cp -d --preserve=timestamps $file $1$file 16 | done 17 | 18 | -------------------------------------------------------------------------------- /stealth/icmake/uninstall: -------------------------------------------------------------------------------- 1 | void uninstall(string logfile) 2 | { 3 | int idx; 4 | list entry; 5 | string dir; 6 | list line; 7 | 8 | if (!exists(logfile)) 9 | { 10 | printf("installation log file " + logfile + " not found\n"); 11 | exit(0); 12 | } 13 | 14 | run("icmake/remove " + logfile + " " + (string)g_echo); 15 | 16 | exit(0); 17 | } 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /stealth/stealth/policymode.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | // Called by main() once all preliminary actions have been completed. 4 | 5 | void Stealth::policyMode() 6 | { 7 | d_logUnit.setupLogs(); 8 | setUniquePtrs(); 9 | 10 | if (d_options.daemon()) 11 | fork(); // creates the daemon. Its childProcess 12 | else // does the tasks. 13 | doTasks(); 14 | } 15 | -------------------------------------------------------------------------------- /stealth/integrityscanner/addto.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::add(std::string const &line, StringVector &skipFiles) 4 | { 5 | string &&trimmed = String::trim(line); 6 | 7 | if (trimmed.empty() || *trimmed.begin() == '#') // skip empty lines and 8 | return; // comment 9 | 10 | skipFiles.push_back(trimmed); 11 | } 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /stealth/runmode/data.cc: -------------------------------------------------------------------------------- 1 | #include "runmode.ih" 2 | 3 | LinearMap const RunMode::s_modeName = 4 | { 5 | {INTEGRITY_SCAN, "INTEGRITY_SCAN"}, 6 | {RERUN, "RERUN"}, 7 | {SUSPEND, "SUSPEND"}, 8 | {RESUME, "RESUME"}, 9 | {RELOAD, "RELOAD"}, 10 | {TERMINATE, "TERMINATE"}, 11 | }; 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /stealth/stealth/autoscan.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | // automatically switch to an integrity scan after reload, rerun and resume. 4 | 5 | void Stealth::autoScan(char const *label) 6 | { 7 | m2 << "automatically starting an INTEGRITY_SCAN following --" << label 8 | << endl; 9 | d_task.setMode(INTEGRITY_SCAN); 10 | d_autoJob = true; 11 | d_job.notify(); 12 | } 13 | -------------------------------------------------------------------------------- /stealth/icmake/log: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find tmp/install -type f -exec md5sum "{}" \; | 4 | sed 's|tmp/install|'$1'|' > $2 5 | find tmp/install -type l -exec printf "link %s\n" "{}" \; | 6 | sed 's|tmp/install|'$1'|' >> $2 7 | find tmp/install -type d -exec printf "dir %s\n" "{}" \; | 8 | sed 's|tmp/install|'$1'|' >> $2 9 | 10 | -------------------------------------------------------------------------------- /stealth/syslogstruct/syslogstruct.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_SYSLOGSTRUCT_ 2 | #define INCLUDED_SYSLOGSTRUCT_ 3 | 4 | #include 5 | #include 6 | 7 | struct SyslogStruct 8 | { 9 | bool requested; 10 | FBB::Priority priority; 11 | FBB::Facility facility; 12 | std::string tag; 13 | 14 | SyslogStruct(); 15 | }; 16 | 17 | inline SyslogStruct::SyslogStruct() 18 | : 19 | requested(false) 20 | {} 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /stealth/CLASSES: -------------------------------------------------------------------------------- 1 | syslogstruct 2 | 3 | msg 4 | 5 | util 6 | 7 | stealthenums 8 | 9 | options stealthenums syslogstruct msg util 10 | 11 | policyfile options 12 | 13 | runmode stealthenums 14 | 15 | report policyfile 16 | 17 | integrityscanner policyfile runmode 18 | 19 | logunit options 20 | 21 | stealth logunit integrityscanner report 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /stealth/options/requiresomeargument.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::requireSomeArgument() 4 | { 5 | // --help and --version already handled by versionHelp, but if nothing 6 | // is requested on the command line help is also provided. 7 | 8 | if ( 9 | d_arg.nArgs() == 0 && d_arg.nOptions() == 0 && 10 | d_arg.nLongOptions() == 0 11 | ) 12 | { 13 | usage(d_arg.basename()); 14 | throw 0; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /stealth/icmake/pathfile: -------------------------------------------------------------------------------- 1 | list path_file(string path) 2 | { 3 | list ret; 4 | int len; 5 | int idx; 6 | 7 | for (len = strlen(path), idx = len; idx--; ) 8 | { 9 | if (path[idx] == "/") 10 | { 11 | ret = 12 | (list)substr(path, 0, idx) + (list)substr(path, idx + 1, len); 13 | return ret; 14 | } 15 | } 16 | 17 | ret = (list)"" + (list)path; 18 | return ret; 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /stealth/integrityscanner/replace.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::replace(std::string &str, char const *org, 4 | char const *replacement) 5 | { 6 | size_t orglen = strlen(org); 7 | 8 | while (true) 9 | { 10 | string::size_type idx = str.find(org); 11 | 12 | if (idx == string::npos) 13 | break; 14 | 15 | str.replace(idx, orglen, replacement); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /stealth/options/options.ih: -------------------------------------------------------------------------------- 1 | #include "options.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "../msg/msg.h" 10 | #include "../util/util.h" 11 | 12 | void usage(std::string const &progname); 13 | 14 | namespace Icmbuild 15 | { 16 | extern char version[]; 17 | extern char years[]; 18 | extern char author[]; 19 | }; 20 | 21 | using namespace std; 22 | using namespace FBB; 23 | 24 | 25 | -------------------------------------------------------------------------------- /stealth/stealth/suspendrequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | string Stealth::suspendRequest() 4 | { 5 | string ret; 6 | 7 | switch (d_task.mode()) 8 | { 9 | case INTEGRITY_SCAN: 10 | ret = acceptMode(SUSPEND); 11 | break; 12 | 13 | case SUSPEND: 14 | ret = "nop"; 15 | break; 16 | 17 | default: 18 | ret = deniedMode("--suspend"); 19 | break; 20 | } 21 | 22 | return ret; 23 | } 24 | -------------------------------------------------------------------------------- /stealth/util/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDED_UTIL_H_ 2 | #define _INCLUDED_UTIL_H_ 3 | 4 | #include 5 | 6 | class Util 7 | { 8 | public: 9 | static bool mkdir(std::string const &path); // pathname to a file 10 | // find full path name 11 | static std::string realPath(std::string const &path); 12 | static void absPath(std::string const &path, std::string &fileName); 13 | }; 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /stealth/stealth/integrityscan.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::integrityScan() 4 | { 5 | d_report->scanHeader(); 6 | 7 | if (d_options.dryrun()) 8 | { 9 | *d_report << "--dry-run: would have performed an integrity scan" << 10 | endl; 11 | return; 12 | } 13 | 14 | d_integrityScanner->run(); 15 | m2 << "Integrity scan completed" << endl; 16 | } 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /stealth/integrityscanner/loadskipfiles.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::loadSkipFiles() 4 | { 5 | d_skipFile = d_options.skipFile(); 6 | 7 | if (d_skipFile.length()) // skip files 8 | setSkip(); 9 | else // or don't skip 10 | d_skip = &IntegrityScanner::dontSkip; 11 | 12 | m3 << "loadSkipFiles: " << d_skipFiles.size() << " lines" << endl; 13 | } 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /stealth/logunit/newsyslogstream.cc: -------------------------------------------------------------------------------- 1 | #include "logunit.ih" 2 | 3 | ostream *LogUnit::newSyslogStream() 4 | try 5 | { 6 | SyslogStruct const &info = d_options.syslogStruct(); 7 | 8 | return info.requested ? 9 | new SyslogStream(info.tag, info.priority, info.facility) 10 | : 11 | 0; 12 | } 13 | catch (exception const &exc) 14 | { 15 | fmsg << "cannot write syslog messages" << noidl; 16 | return 0; // to make the compiler happy 17 | } 18 | -------------------------------------------------------------------------------- /stealth/options/setskipfile.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | int Options::setSkipFile() 4 | { 5 | if ((d_cmdLineOption & SKIP_FILE) or not d_arg.option(&d_skipFile, 's')) 6 | return 0; 7 | 8 | if (d_arg.nArgs() == 0) 9 | fmsg << "--skip-files: missing skip-file or policy file" << noidl; 10 | 11 | if (d_ipc) 12 | fmsg << "--skip-files incompatible with IPC calls" << noidl; 13 | 14 | Util::absPath(d_base, d_skipFile); 15 | 16 | return SKIP_FILE; 17 | } 18 | -------------------------------------------------------------------------------- /stealth/integrityscanner/skip.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | bool IntegrityScanner::skip(string &line) 4 | { 5 | auto end = d_skipFiles.end(); 6 | 7 | return 8 | end != find_if( 9 | d_skipFiles.begin(), end, 10 | [&](string const &skip) // skip: entry to skip 11 | { 12 | return skipDecision(line, skip); 13 | } 14 | ); 15 | } 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /stealth/options/setsyslog.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setSyslog() 4 | { 5 | d_syslogStruct.requested = d_arg.option(0, "syslog"); 6 | 7 | if (not d_syslogStruct.requested) 8 | return; 9 | 10 | if (d_ipc) 11 | fmsg << "--syslog* options incompatible with IPC calls" << noidl; 12 | 13 | 14 | if (not d_arg.option(&d_syslogStruct.tag, "syslog-tag")) 15 | d_syslogStruct.tag = s_defaultSyslogIdent; 16 | 17 | setSyslogPriority(); 18 | setSyslogFacility(); 19 | } 20 | -------------------------------------------------------------------------------- /stealth/options/setrandomdelay.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setRandomDelay() 4 | { 5 | string delay; 6 | 7 | // no option initializes to 0 8 | if (not (d_randomDelay = d_arg.option(&delay, 'i'))) 9 | return; 10 | 11 | if (not d_repeat) 12 | fmsg << "--random-interval requires --repeat" << noidl; 13 | 14 | d_delayInterval = checkM(delay, "random-interval"); 15 | 16 | srandom(time(0)); // seed the random time generator 17 | } 18 | -------------------------------------------------------------------------------- /stealth/options/settimestamp.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setTimestamp() 4 | { 5 | string value; 6 | if (not d_arg.option(&value, 't')) 7 | return; 8 | 9 | if (value == "LT") 10 | d_timestamp = TIMESTAMPS; 11 | else if (value == "UTC") 12 | d_timestamp = UTCTIMESTAMPS; 13 | else if (value != "UTC") 14 | wmsg << "--time-stamp " << value << " not supported. Using UTC" << 15 | endl; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /stealth/integrityscanner/waitforsentinel.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // SEE ALSO THE MEMBER copy() 4 | 5 | void IntegrityScanner::waitForSentinel(Process &extractor) 6 | { 7 | string line; 8 | 9 | while (getline(extractor, line)) 10 | { 11 | m3 << "read line `" << line << '\'' << endl; 12 | 13 | if (line.find(d_sentinel) == 0) 14 | { 15 | m3 << "GOT Sentinel" << endl; 16 | break; 17 | } 18 | } 19 | 20 | testExitValue(extractor.str(), line); 21 | } 22 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/checkingsetuid.yo: -------------------------------------------------------------------------------- 1 | Having checked the client's tt(sha1sum) and tt(find) programs, sha1 checksum 2 | checks should be performed on all setuid and setgid files on the 3 | client. For this we activate the tt(sha1sum) program on the client. In 4 | order to check the setuid/setgid files, the following command is added to the 5 | policy file: 6 | verb( 7 | LABEL \nsuid/sgid/executable files uid or gid root on the / partition 8 | CHECK LOG = remote/setuidgid /usr/bin/find / ${EXECSHA1}) 9 | 10 | -------------------------------------------------------------------------------- /stealth/report/report.ih: -------------------------------------------------------------------------------- 1 | #include "report.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../options/options.h" 11 | #include "../msg/msg.h" 12 | #include "../policyfile/policyfile.h" 13 | 14 | namespace Icmbuild 15 | { 16 | extern char const version[]; 17 | } 18 | 19 | using namespace FBB; 20 | using namespace std; 21 | 22 | inline ios::pos_type Report::endpos() 23 | { 24 | return seekp(0, ios::end).tellp(); 25 | } 26 | -------------------------------------------------------------------------------- /stealth/ACKNOWLEDGEMENTS: -------------------------------------------------------------------------------- 1 | The following persons have been very helpful in developing and testing 2 | STEALTH: 3 | 4 | Hans Gankema , 5 | For formulating the initial idea behind `stealth' 6 | 7 | Kees Visser 8 | For formulating the initial idea behind `stealth' 9 | 10 | Hopko Meijering 11 | For testing stealth on various computers, and for proofreading 12 | the documentation 13 | 14 | 15 | Thanks! 16 | 17 | Frank. 18 | 19 | 20 | -------------------------------------------------------------------------------- /stealth/integrityscanner/setskip.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::setSkip() 4 | { 5 | ifstream in(d_skipFile); 6 | if (not in) 7 | fmsg << "cannot read skip-file `" << d_skipFile << '\'' << noidl; 8 | 9 | for_each( 10 | istream_iterator(in), istream_iterator(), 11 | [&](std::string const &line) 12 | { 13 | add(line, d_skipFiles); 14 | } 15 | ); 16 | 17 | d_skip = &IntegrityScanner::skip; 18 | } 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /stealth/integrityscanner/getpath.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | string IntegrityScanner::getPath(string const &orgLine) const 4 | { 5 | size_t pathPos = 6 | d_pathOffset == numeric_limits::max() ? 7 | orgLine.find_first_of('/') 8 | 9 | : d_pathOffset < orgLine.length() ? 10 | d_pathOffset 11 | : 12 | string::npos; 13 | 14 | string path; 15 | 16 | if (pathPos != string::npos) 17 | path = String::trim(orgLine.substr(pathPos)); 18 | 19 | 20 | return path; 21 | } 22 | -------------------------------------------------------------------------------- /stealth/stealth/childprocess.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::childProcess() 4 | { 5 | // prepareDaemon("/tmp/serr", "/tmp/serr"); // by Fork. 6 | prepareDaemon(); // by Fork. 7 | 8 | // start the ipc interface thread 9 | thread(startThread, &Stealth::ipcInterface, this).detach(); 10 | 11 | doTasks(); 12 | 13 | m1 << d_options.basename() << " (process " << getpid() << 14 | ") terminates" << endl; 15 | throw 0; 16 | } 17 | -------------------------------------------------------------------------------- /stealth/util/mkdir.cc: -------------------------------------------------------------------------------- 1 | #include "util.ih" 2 | 3 | bool Util::mkdir(string const &path) 4 | { 5 | char buffer[path.length() + 1]; 6 | 7 | buffer[path.copy(buffer, string::npos)] = 0; // copy the path 8 | char const *dir = dirname(buffer); // construct the dirname 9 | 10 | return 11 | ( 12 | !::mkdir(dir, S_IRWXU) // constructing dir ok, 13 | || // (only drwx------) 14 | errno == EEXIST // or dir already existed 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /stealth/documentation/example-policies/simple.pol: -------------------------------------------------------------------------------- 1 | # this policy will scan the files in /bin, writing the results in /tmp. 2 | # the base directory is SIMPLE 3 | # The user running stealth should be able to make an ssh connection to itself. 4 | # Use this file with, e.g., ./stealth simple.pol 5 | 6 | # set up the non-default USE variables 7 | USE BASE SIMPLE 8 | USE MAILER ../stealthmail 9 | USE MAILARGS -s "simple STEALTH report" 10 | USE SSH /usr/bin/ssh localhost -q 11 | 12 | CHECK bin /usr/bin/find /bin -xdev -type f -exec /usr/bin/sha1sum {} \; 13 | -------------------------------------------------------------------------------- /stealth/icmake/md: -------------------------------------------------------------------------------- 1 | // md: target should be a series of blank-delimited directories to be created 2 | // If an element is a whildcard, the directory will always be created, 3 | // using mkdir -p. 4 | // 5 | // uses: run() 6 | 7 | void md(string target) 8 | { 9 | int idx; 10 | list paths; 11 | string dir; 12 | 13 | if (!exists(target)) 14 | run("mkdir -p " + target); 15 | else if (((int)stat(target)[0] & S_IFDIR) == 0) 16 | { 17 | printf(target + " exists, but is not a directory\n"); 18 | exit(1); 19 | } 20 | } 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | The STEALTH program performs File Integrity Checks on (remote) clients. It 2 | differs from other File Integrity Checkers by not requiring baseline integrity 3 | data to be kept on either write-only media or in the client's file system. In 4 | fact, clients will hardly contain any indication suggesting that they are 5 | being monitored, thus improving the stealthiness of the integrity scans. 6 | 7 | 8 | Stealth's repository has moved to https://gitlab.com/fbb-git/stealth 9 | and is not maintained at this location anymore. 10 | 11 | The project's web-page can be found at http://fbb-git.gitlab.io/stealth/ 12 | 13 | -------------------------------------------------------------------------------- /stealth/integrityscanner/putcommand.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | string IntegrityScanner::putCommand(string const &source, 4 | string const &destination) const 5 | { 6 | struct stat statbuf; 7 | 8 | if (stat(source.c_str(), &statbuf)) 9 | fmsg << "PUT " << source << ": can't stat it" << noidl; 10 | 11 | ostringstream command; 12 | 13 | command << d_policyFile["DD"] << " of=" << destination << 14 | " bs=1 count=" << statbuf.st_size; 15 | 16 | return command.str(); 17 | } 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /stealth/options/setsyslogfacility.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setSyslogFacility() 4 | { 5 | string option; 6 | if (not d_arg.option(&option, "syslog-facility")) 7 | d_syslogStruct.facility = s_defaultSyslogFacility; 8 | else 9 | { 10 | LinearMap::const_iterator 11 | iter = s_syslogFacilities.find(option); 12 | 13 | if (iter == s_syslogFacilities.end()) 14 | fmsg << "syslog facility " << option << " not supported" << noidl; 15 | 16 | d_syslogStruct.facility = iter->second; 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /stealth/options/setrepeat.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setRepeat() 4 | { 5 | string value; 6 | 7 | if (not (d_repeat = d_arg.option(&value, "repeat"))) 8 | return; 9 | 10 | if (d_ipc) 11 | fmsg << "--repeat not available in IPC modes" << noidl; 12 | 13 | d_repeatInterval = checkM(value, "repeat"); 14 | 15 | if (d_repeatInterval == 0) 16 | wmsg << "--repeat 0: no repeated integrity scans" << endl; 17 | 18 | if (d_repeatInterval > static_cast(numeric_limits::max())) 19 | d_repeatInterval = numeric_limits::max(); 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /stealth/options/setsyslogpriority.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setSyslogPriority() 4 | { 5 | string option; 6 | if (not d_arg.option(&option, "syslog-priority")) 7 | d_syslogStruct.priority = s_defaultSyslogPriority; 8 | else 9 | { 10 | LinearMap::const_iterator 11 | iter = s_syslogPriorities.find(option); 12 | 13 | if (iter == s_syslogPriorities.end()) 14 | fmsg << "syslog priority " << option << " not supported" << noidl; 15 | 16 | d_syslogStruct.priority = iter->second; 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /stealth/integrityscanner/foreground.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::foreground(size_t cmdNr) 4 | { 5 | cout.clear(); 6 | 7 | if (cmdNr > d_policyFile.size()) 8 | imsg << "cannot run policy command #" << cmdNr << " out of " << 9 | d_policyFile.size() << endl; 10 | else 11 | { 12 | d_cmdIterator += cmdNr - 1; // if so, set the cmdIterator 13 | execute(*d_cmdIterator); // and execute that command 14 | } 15 | 16 | cout.setstate(ios::failbit); 17 | } 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /stealth/msg/msg.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_MSG_ 2 | #define INCLUDED_MSG_ 3 | 4 | #include 5 | 6 | class Msg: public std::ostream 7 | { 8 | public: 9 | Msg(); // msgs are inserted if verbosity <= 10 | // the configured verbosity level 11 | // E.g., configured: 3 inserts m1, m2 and m3 12 | 13 | Msg(std::ostream &out); // Used by mp, writing to cout 14 | 15 | static void setVerbosity(size_t verbosity); 16 | }; 17 | 18 | extern Msg m1; 19 | extern Msg m2; 20 | extern Msg m3; 21 | 22 | extern Msg mp; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /stealth/options/checkm.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | size_t Options::checkM(string const &spec, char const *option) const 4 | try 5 | { 6 | size_t pos; 7 | size_t ret = stoul(spec, &pos); 8 | 9 | char ch = spec[pos]; 10 | 11 | if (ch == 'm') 12 | ret *= 60; 13 | else if (isprint(ch)) 14 | wmsg << '`' << ch << "' in --" << option << ' ' << spec << 15 | " ignored" << endl; 16 | return ret; 17 | } 18 | catch (...) 19 | { 20 | fmsg << "Invalid --" << option << " specified" << noidl; 21 | return 0; 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/checkingconfig.yo: -------------------------------------------------------------------------------- 1 | Finally, the client's configuration files are checked. Some of these files 2 | change so frequently that we don't want them to be checked. E.g., 3 | tt(/etc/adjtime, /etc/mtab). To check the configuration file, do: 4 | COMMENT( 5 | NOTE: KEEP THE BLANKS AFTER THE BACKSLASHES 6 | END) 7 | verb( LABEL \nconfiguration files under /etc 8 | CHECK LOG = remote/etcfiles \ 9 | /usr/bin/find /etc -type f -not -perm /6111 \ 10 | -not -regex "/etc/\(adjtime\|mtab\)" \ 11 | -exec /usr/bin/sha1sum {} \;) 12 | -------------------------------------------------------------------------------- /stealth/stealth/dotasks.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::doTasks() 4 | { 5 | if (not d_options.ipc()) 6 | { 7 | m1 << "timestamps use " << 8 | (d_options.timestamp() == TIMESTAMPS ? 9 | "local time" 10 | : 11 | "UTC" 12 | ) << endl; 13 | } 14 | 15 | d_policyFile->chdirBase(); 16 | 17 | if (d_options.dryrun()) 18 | *d_report << "--dry-run: SH/SSH connections not established" << endl; 19 | else 20 | d_integrityScanner->startCommandShells(); 21 | 22 | jobsHandler(); 23 | } 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /stealth/documentation/manual/stealth.sty: -------------------------------------------------------------------------------- 1 | \sloppy 2 | \renewcommand*\l@subsection{\@dottedtocline{2}{3.8em}{3.7em}} 3 | \addtolength{\textheight}{2cm} 4 | \addtolength{\textwidth}{4cm} 5 | %\addtolength{\hoffset}{-2cm} 6 | 7 | \usepackage[bookmarks=true, 8 | %pagebackref,% 9 | colorlinks=true,% 10 | frenchlinks=false,% set links in small-caps font instead of color. 11 | linkcolor=blue,% 12 | urlcolor=blue,% 13 | citecolor=blue,% citation reference color 14 | filecolor=blue,% 15 | pdfpagemode=None,% don't show thumbs/bookmarks 16 | pdfstartview=FitH,% window fits Horizontal (width) page dimension 17 | ]{hyperref} %must be last package loaded!! 18 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/installing.yo: -------------------------------------------------------------------------------- 1 | As s() is mainly a system administrator's tool, it could be 2 | installed in tt(/usr/bin). In that case, do (as em(root)) in the 3 | directory where s() was compiled/unpacked: 4 | verb( ./build install program) 5 | Alternatively, another default location may be specified in the 6 | tt(INSTALL.im) file or may be provided to the tt(build) script. E.g., 7 | verb( ./build install program /usr/local/bin/stealth) 8 | installing the binary program as tt(/usr/local/bin/stealth). 9 | 10 | The provided tt(icmake build) script can be started without arguments for an 11 | overview of possible commands. 12 | 13 | 14 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/intro.yo: -------------------------------------------------------------------------------- 1 | Now that s() has been compiled, the construction of a policy file has 2 | been covered, and a service-account on the client has been defined, what must 3 | be done to run s() in practice? 4 | 5 | Here's what remains to be done: 6 | itemization( 7 | it() Install s() at a proper location 8 | it() Construct one or more policy files 9 | it() Learn to interpret s()'s output. 10 | it() Optionally, automate the removal of old log-files. 11 | it() Determine a schedule for running stealth automatically, e.g. using 12 | bf(cron)(1) or bf(ssh-cron)(1) 13 | ) 14 | In this chapter, these topics are discussed. 15 | 16 | -------------------------------------------------------------------------------- /stealth/icmconf: -------------------------------------------------------------------------------- 1 | #include "INSTALL.im" 2 | 3 | #undef CXXFLAGS 4 | #define CXXFLAGS "-Wall -O2 -pthread" 5 | 6 | #define MAIN "main.cc" 7 | #define ADD_LIBRARIES "bobcat" 8 | #define ADD_LIBRARY_PATHS "" 9 | #define REFRESH 10 | #define LIBRARY "modules" 11 | #define IH ".ih" 12 | #define PRECOMP "-x c++-header" 13 | #define SHAREDREQ "" 14 | #define USE_ALL "a" 15 | #define SOURCES "*.cc" 16 | #define USE_ECHO ON 17 | #define TMP_DIR "tmp" 18 | #define OBJ_EXT ".o" 19 | #define USE_VERSION 20 | #define DEFCOM "program" 21 | 22 | 23 | -------------------------------------------------------------------------------- /stealth/policyfile/load.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::load() 4 | { 5 | d_use = LinearMap( 6 | &s_defaultKeyword[0], &s_defaultKeyword[s_nDefaultKeywords] 7 | ); 8 | 9 | d_define.clear(); 10 | d_command.clear(); 11 | 12 | fetchCommands(); 13 | 14 | string &base = d_use["BASE"]; 15 | 16 | base += '.'; // the . is required by mkdir 17 | char const *cp = base.c_str(); 18 | Util::mkdir(cp); 19 | base.pop_back(); // cut off the . again 20 | 21 | chdirBase(); // change to the base directory 22 | } 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /stealth/policyfile/policyfile.ih: -------------------------------------------------------------------------------- 1 | #include "policyfile.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../util/util.h" 10 | #include "../msg/msg.h" 11 | #include "../options/options.h" 12 | 13 | using namespace std; 14 | using namespace FBB; 15 | 16 | inline std::string const &PolicyFile::getDEFINE( 17 | std::string const &key) const 18 | { 19 | return d_define.find(key)->second; 20 | } 21 | 22 | inline bool PolicyFile::hasDEFINE(std::string const &key) const 23 | { 24 | return d_define.count(key); 25 | } 26 | -------------------------------------------------------------------------------- /stealth/integrityscanner/nextcommand.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::nextCommand(ostream &out, string const &command) 4 | { 5 | m3 << "nextCommand: inserting\n" << command << "\n" 6 | "and: echo " << d_sentinel << " $?" << endl; 7 | 8 | // run the command, then 9 | // echo the sentinel and returnvalue 10 | out << command << "\n" 11 | "/bin/echo \"" << d_sentinel << " $?\"" << endl; 12 | 13 | if (!out) 14 | fmsg << "Inserting command `" << s_firstWord[0] << "' failed." << 15 | noidl; 16 | } 17 | -------------------------------------------------------------------------------- /stealth/policyfile/insert.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::insert(LinearMap &linMap, string const &line) 4 | { 5 | if (s_firstWord << s_firstWord[2]) // fetch 'KEY definition' 6 | { 7 | string type = s_firstWord[1]; 8 | 9 | mp << type << " line: " << line << endl; 10 | linMap[s_firstWord[1]] = s_firstWord[2]; // store key and value 11 | mp << type << " key: " << s_firstWord[1] << 12 | ", value: " << linMap[s_firstWord[1]] << endl; 13 | return; 14 | } 15 | // error on failure 16 | imsg << "Format error: ignored `" << line << "'\n"; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /stealth/icmake/findall: -------------------------------------------------------------------------------- 1 | // assuming we're in g_cwd, all entries of type 'type' matching source/pattern 2 | // are returned w/o final \n 3 | 4 | list findAll(string type, string source, string pattern) 5 | { 6 | string cmd; 7 | list entries; 8 | list ret; 9 | int idx; 10 | 11 | chdir(source); 12 | 13 | cmd = "find ./ -mindepth 1 -maxdepth 1 -type " + type; 14 | 15 | if (pattern != "") 16 | pattern = "-name '" + pattern + "'"; 17 | 18 | entries = backtick(cmd + " " + pattern + " -printf \"%f\\n\""); 19 | 20 | for (idx = listlen(entries); idx--; ) 21 | ret += (list)cutEoln(entries[idx]); 22 | 23 | chdir(g_cwd); 24 | 25 | return ret; 26 | } 27 | -------------------------------------------------------------------------------- /stealth/stealth/setuniqueptrs.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::setUniquePtrs() 4 | { 5 | d_policyFile.reset(new PolicyFile(d_options)); // the PolicyFile may 6 | // redefine some options 7 | 8 | d_report.reset(new Report(d_options, *d_policyFile)); 9 | 10 | d_integrityScanner.reset( 11 | new IntegrityScanner(d_pending, d_options, *d_policyFile, *d_report) 12 | ); 13 | 14 | setupFatalReport(); 15 | 16 | d_logUnit.setupLogs(d_logReport); // possibly redefine the log files 17 | 18 | m2 << "constructed the Integrity Scanner" << endl; 19 | m3 << "max. download size: " << d_options.maxSizeStr() << endl; 20 | } 21 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/define.yo: -------------------------------------------------------------------------------- 1 | First we write some tt(DEFINE) directives simplifying complex command 2 | specifications: 3 | verb( 4 | DEFINE SSHCMD /usr/bin/ssh root@client -T -q exec /bin/bash --noprofile 5 | DEFINE EXECSHA1 -xdev -perm +u+s,g+s \( -user root -or -group root \) \ 6 | -type f -exec /usr/bin/sha1sum {} \;) 7 | The first tt(DEFINE) defines the tt(ssh) command to use: an ssh-connection 8 | will be made to the root account at the client. 9 | 10 | The second tt(DEFINE) shows the arguments for bf(find)(1) when looking for 11 | all root setuid or setgid normal files. For all these files the bf(sha1sum)(1) 12 | program should be run. 13 | 14 | -------------------------------------------------------------------------------- /stealth/msg/setverbosity.cc: -------------------------------------------------------------------------------- 1 | #include "msg.ih" 2 | 3 | void Msg::setVerbosity(size_t verbosity) 4 | { 5 | // switch off all mx streams exceeding verbosity 6 | switch (verbosity) 7 | { 8 | case 0: 9 | m1.setstate(ios::failbit); 10 | case 1: 11 | m2.setstate(ios::failbit); 12 | case 2: 13 | m3.setstate(ios::failbit); 14 | } 15 | 16 | // switch on all mx streams up to verbosity 17 | switch (verbosity) 18 | { 19 | case 3: 20 | m3.clear(); 21 | case 2: 22 | m2.clear(); 23 | case 1: 24 | m1.clear(); 25 | } 26 | } 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /stealth/integrityscanner/integrityscanner.ih: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../util/util.h" 13 | #include "../policyfile/policyfile.h" 14 | #include "../runmode/runmode.h" 15 | #include "../options/options.h" 16 | #include "../msg/msg.h" 17 | 18 | 19 | using namespace std; 20 | using namespace FBB; 21 | 22 | inline bool IntegrityScanner::dontSkip(std::string &line) 23 | { 24 | return false; // by returning false the question 25 | // 'skip line?' is always answered as 'no' 26 | } 27 | 28 | -------------------------------------------------------------------------------- /stealth/integrityscanner/testexitvalue.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::testExitValue(std::string const &cmd, 4 | std::string const &exitStr) 5 | { 6 | if (not (s_exitValue << exitStr)) 7 | fmsg << "No exit value for\n" << 8 | cmd << "\n" 9 | "ADVICE: this is the literal text of the executed command. " 10 | "Maybe a typo?" << noidl; 11 | 12 | if (d_testExitValue && stoul(s_exitValue[1]) != 0) 13 | fmsg << d_options.basename() << 14 | " terminated: non-zero exit value for\n" << 15 | *d_cmdIterator << " (" << exitStr << ")" << noidl; 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/mailed.yo: -------------------------------------------------------------------------------- 1 | The tt(/root/bin/stealthmail) script is called with the following arguments: 2 | verb( 3 | "Client STEALTH report" admin@elswhere) 4 | 5 | The mailed report contains information comparable to this: 6 | verb( 7 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:10:56 +0100 8 | 9 | Check the client's sha1sum program 10 | Initialized report on local/sha1 11 | 12 | checking the client's /usr/bin/find program 13 | Initialized report on remote/binfind 14 | 15 | suid/sgid/executable files uid or gid root on the / partition 16 | Initialized report on remote/setuidgid 17 | 18 | configuration files under /etc 19 | Initialized report on remote/etcfiles) 20 | -------------------------------------------------------------------------------- /stealth/integrityscanner/checksize.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::checkSize(std::string const &fname, off_t length) 4 | { 5 | if (length > d_maxSize) 6 | fmsg << 7 | "STEALTH - CAN'T CONTINUE: `" << fname << "' EXCEEDS MAX. " 8 | "DOWNLOAD SIZE (" << d_options.maxSizeStr() << ")\n" 9 | "STEALTH - THIS COULD POINT TO A SERIOUS SITUATION EXISTING AT " 10 | "THE CLIENT\n" 11 | "STEALTH - THIS CONDITION MAY HAVE INVALIDATED THE CLIENT'S LOG " 12 | "FILES\n" 13 | "STEALTH - *** INVESTIGATE ***" << noidl; 14 | } 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /stealth/integrityscanner/write.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // SEE ALSO THE MEMBER waitForSentinel() 4 | 5 | void IntegrityScanner::write(string const &fname) 6 | { 7 | ifstream source(fname.c_str()); 8 | 9 | if (!source) 10 | fmsg << "can't read `" << fname << '\'' << noidl; 11 | 12 | m3 << "about to read local `" << fname << '\'' << endl; 13 | 14 | while (true) 15 | { 16 | size_t const SIZEOF_BUF = 1000; 17 | char buffer[SIZEOF_BUF]; 18 | 19 | size_t nRead = source.read(buffer, SIZEOF_BUF).gcount(); 20 | 21 | if (!nRead) 22 | break; 23 | 24 | if (!d_sshFork.write(buffer, nRead)) 25 | fmsg << "PUT failed." << noidl; 26 | } 27 | 28 | d_sshFork.flush(); 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /stealth/policyfile/loadoptions.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::loadOptions(ConfigFile &configFile, size_t from) 4 | { 5 | TempStream tmpStream(User().homedir() + s_configFileBase); 6 | 7 | for 8 | ( 9 | auto begin = configFile.begin() + from, end = configFile.end(); 10 | begin != end; 11 | ++begin 12 | ) 13 | tmpStream << *begin << '\n'; // copy the long options 14 | // into the temp. stream 15 | 16 | tmpStream.close(); 17 | 18 | // read the config file's options 19 | ArgConfig::instance().open(tmpStream.fileName()); 20 | 21 | d_options.setConfigOptions(); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /stealth/documentation/manual/access/using.yo: -------------------------------------------------------------------------------- 1 | On order to minimize the amount of clutter and possibly complications when 2 | only a simple command-shell is required for executing commands, it is 3 | suggested to use a bf(bash)(1) shell when logging into tt(account@client)'s 4 | account. 5 | 6 | When another shell is already used for tt(account@client), then an extra 7 | account (optionally using the same tt(UID) as the original account, but using 8 | bf(sh)(1) as the shell), could be defined in the client's tt(/etc/passwd) 9 | file. In the bf(passwd)(5) file this could, e.g., be realized for em(root) as 10 | em(rootsh) as follows:nl() 11 | verb( rootsh:x:0:0:root:/root:/bin/bash) 12 | If shadow passwording is used, a matching entry in the tt(/etc/shadow) 13 | file is required as well. 14 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/checkingfind.yo: -------------------------------------------------------------------------------- 1 | The client normally uses its tt(find) command intensively: tt(find) is a 2 | great tool for producing reports about almost any conceivable combination of 3 | characteristics of sets of files. Of course, the client's tt(find) command 4 | must itself be OK, as well as the client's tt(sha1sum) program. Now that we 5 | know that the client's tt(sha1sum) program is OK, we can use it to check the 6 | client's tt(/usr/bin/find) program. 7 | 8 | Note that the monitor itself no longer needs to invest any significant 9 | processing load: only the client itself is taxed for checking the integrity 10 | of its own files: 11 | verb( 12 | LABEL \nchecking the client's /usr/bin/find program 13 | CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find) 14 | 15 | -------------------------------------------------------------------------------- /stealth/options/setcommandnr.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setCommandNr() 4 | { 5 | string value; 6 | if (not d_arg.option(&value, 'r')) 7 | return; 8 | 9 | foregroundOnly("run-command"); 10 | 11 | try 12 | { 13 | d_commandNr = stoul(value); 14 | if (d_commandNr == 0) 15 | fmsg << "--run-command 0: not a valid (natural) command number" << 16 | noidl; 17 | if (not d_stdout) 18 | d_stdout = true; 19 | } 20 | catch (...) 21 | { 22 | d_commandNr = 0; 23 | fmsg << "--run-command " << value << ": invalid command number" << 24 | noidl; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /stealth/required: -------------------------------------------------------------------------------- 1 | This file lists non-standard software only. Thus, standard utilities like cp, 2 | mv, sed, etc, etc, are not explicitly mentioned. Neither is the gcc compiler 3 | explicitly mentioned, but a fairly recent one is assumed. 4 | 5 | Required software for building Stealth: 6 | --------------------------------------- 7 | 8 | Latest versions of: 9 | 10 | libbobcat-dev (cf. https://fbb-git.github.io/bobcat/) 11 | icmake (cf. https://fbb-git.github.io/icmake/) 12 | yodl (cf. https://fbb-git.github.io/yodl/) 13 | 14 | To construct the user guide: 15 | 16 | texlive-latex-base, 17 | texlive-generic-recommended, 18 | texlive-latex-recommended, 19 | texlive-latex-extra, 20 | texlive-fonts-recommended, 21 | cm-super-minimal, 22 | ghostscript 23 | 24 | 25 | -------------------------------------------------------------------------------- /stealth/documentation/manual/access/client.yo: -------------------------------------------------------------------------------- 1 | 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 monitor's user. To do so, the monitor user's file 4 | tt(~/.ssh/id_rsa.pub) is added to the client account user's file 5 | tt(~/.ssh/authorized_keys): 6 | verb( # transfer user@monitor's file id_rsa.pub to the client's /tmp 7 | # directory. Then do: 8 | 9 | cat /tmp/id_rsa.pub >> /home/account/.ssh/authorized_keys) 10 | 11 | This allows the user at the monitor to login at the account at the 12 | client without specifying the client account's password (of course, if the 13 | ssh-key is passphrase protected that passphrase must still be provided at the 14 | monitor when starting s()). 15 | 16 | -------------------------------------------------------------------------------- /stealth/icmake/remove: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | g_echo=$2 4 | 5 | rm_f() 6 | { 7 | [ $g_echo -ne 0 ] && echo rm $1 8 | rm -f $1 9 | } 10 | 11 | rm_dir() 12 | { 13 | [ $g_echo -ne 0 ] && echo rmdir $1 14 | rmdir --ignore-fail-on-non-empty -p $1 15 | } 16 | 17 | 18 | IFS=" 19 | " 20 | 21 | for line in `cat $1` 22 | do 23 | field1=`echo $line | awk '{printf $1}'` 24 | field2=`echo $line | awk '{printf $2}'` 25 | 26 | if [ $field1 == "link" ] ; then 27 | rm_f $field2 28 | elif [ $field1 == "dir" ] ; then 29 | rm_dir $field2 30 | elif [ -e "$field2" ] ; then 31 | if [ "$field1" != "`md5sum $field2 | awk '{printf $1}'`" ] ; then 32 | echo $field2 changed, not removed 33 | else 34 | rm_f $field2 35 | fi 36 | fi 37 | done 38 | 39 | rm_f $1 40 | 41 | -------------------------------------------------------------------------------- /stealth/options/checkmode.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::checkMode() const 4 | { 5 | // only one of these options may be specified 6 | 7 | if (d_daemon + d_reload + d_rerun + d_resume + d_suspend + d_terminate > 1) 8 | { 9 | fmsg << "incompatible options:"; 10 | 11 | if (d_daemon) 12 | fmsg << " --daemon"; 13 | 14 | if (d_reload) 15 | fmsg << " --reload"; 16 | 17 | if (d_rerun) 18 | fmsg << " --rerun"; 19 | 20 | if (d_resume) 21 | fmsg << " --resume"; 22 | 23 | if (d_suspend) 24 | fmsg << " --suspend"; 25 | 26 | if (d_terminate) 27 | fmsg << " --terminate"; 28 | 29 | fmsg << noidl; 30 | } 31 | } 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /stealth/policyfile/fixrelativelocations.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::fixRelativeLocations() 4 | { 5 | string const &base = d_use["BASE"]; 6 | 7 | Util::absPath(base, d_use["REPORT"]); 8 | 9 | for (auto &line: d_command) 10 | { 11 | // [LOCAL] CHECK [LOG =] [pathOffset] 12 | // [LOCAL] NOTEST CHECK [pathOffset] 13 | // NOTEST CHECK [LOG =] [pathOffset] 14 | 15 | if (s_log << line) 16 | { 17 | string logName = s_log[4]; 18 | Pattern::Position pos = s_log.position(4); 19 | 20 | Util::absPath(base, logName); 21 | 22 | line.replace(pos.first, pos.second - pos.first, logName); 23 | } 24 | } 25 | } 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /stealth/README.4.00.00: -------------------------------------------------------------------------------- 1 | With Stealth 4.00.00 existing policy files used with Stealth 3.00.00 can 2 | remain as-is, although a run- or pid-file is no longer used. Instead, a Unix 3 | Domain Socket is used for communication between a Stealth daemon and Stealth 4 | running in IPC mode. 5 | 6 | For cosmetic reasons consider using xxx.uds instead of xxx.run or xxx.pid. 7 | 8 | Logrotate.d scripts should use the 'copytruncate' and 'sharedscripts' options 9 | (see the man-page for an example). These options should have been used with 10 | earlier Stealth versions too, but were overlooked until now (sorry about 11 | that). 12 | 13 | If access to the Unix Domain Socket defined by Stealth running in daemon mode 14 | should be restricted, it can be defined in a directory with is only accessible 15 | to the user running Stealth (this will often be the root-user). 16 | -------------------------------------------------------------------------------- /stealth/documentation/example-policies/localhost.pol: -------------------------------------------------------------------------------- 1 | # create several DEFINEs 2 | DEFINE CLIENT localhost 3 | DEFINE SETUID -xdev -type f -perm /u+s,g+s \( -user root -or -group root \) 4 | 5 | # set up the non-default USE variables 6 | USE BASE /root/stealth/${CLIENT} 7 | 8 | USE EMAIL root@${CLIENT} 9 | # USE MAILER /usr/local/bin/stealthmail 10 | USE MAILER /usr/bin/mail 11 | USE MAILARGS -s "${CLIENT} STEALTH report" 12 | 13 | USE SSH /usr/bin/ssh root@${CLIENT} /bin/bash -i 14 | 15 | 16 | LABEL \nroot setuid/setgid files 17 | CHECK LOG = remote/setuid \ 18 | /usr/bin/find / ${SETUID} -exec /usr/bin/sha1sum {} \; 19 | 20 | 21 | LABEL \nfiles in /usr/local/etc 22 | CHECK remote/etcsha1 \ 23 | /usr/bin/find /usr/local/etc -xdev -type f -exec /usr/bin/sha1sum {} \; 24 | -------------------------------------------------------------------------------- /stealth/logunit/logunit.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_LOGUNIT_ 2 | #define INCLUDED_LOGUNIT_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | class Options; 10 | 11 | namespace FBB 12 | { 13 | class LogBuffer; 14 | class Syslogbuf; 15 | } 16 | 17 | class LogUnit 18 | { 19 | Options &d_options; 20 | 21 | std::unique_ptr d_log; 22 | std::unique_ptr d_syslog; 23 | 24 | std::unique_ptr d_imsgbuf; 25 | std::unique_ptr d_fmsgbuf; 26 | 27 | public: 28 | LogUnit(Options &options); 29 | 30 | void setupLogs(); 31 | void setupLogs(std::ostream &report); 32 | 33 | std::ostream *newSyslogStream(); 34 | std::ostream *newLog(); 35 | }; 36 | 37 | #endif 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /stealth/report/report1.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | Report::Report(Options &options, PolicyFile const &policyFile) 4 | : 5 | fstream(policyFile["REPORT"], ios::out | ios::ate | ios::in), 6 | d_name(policyFile["REPORT"]), 7 | d_options(options), 8 | d_policyFile(policyFile) 9 | { 10 | if (not good()) 11 | { 12 | clear(); 13 | open(d_name, ios::out | ios::in | ios::trunc); 14 | } 15 | 16 | if (not good()) 17 | fmsg << "cannot write report file `" << d_name << '\'' << noidl; 18 | 19 | ostringstream headerTxt; 20 | headerTxt << "\n" 21 | "STEALTH (" << Icmbuild::version << ") started at " << 22 | d_options.rfc2822() << '\n'; 23 | 24 | d_headerLine = headerTxt.str(); 25 | 26 | *this << d_headerLine << endl; 27 | 28 | refresh(); 29 | } 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /stealth/stealth/incomingrequest.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | bool Stealth::incomingRequest(istream &in, ostream &out) 4 | { 5 | int request; // read te request 6 | if (not (in >> request).ignore(numeric_limits::max(), '\n')) 7 | request = UNKNOWN; 8 | 9 | RunMode incoming; 10 | incoming.setMode(RunMode::validate(request)); 11 | 12 | string answer = (this->*s_request.find(incoming.mode())->second)(); 13 | 14 | if (not answer.empty()) // error or no operation (nop) 15 | { 16 | if (answer == "nop") 17 | answer.clear(); 18 | 19 | out << answer << endl; 20 | return false; // no-action or error request: 21 | // read the next request 22 | } 23 | 24 | d_pending = incoming; 25 | return true; 26 | } 27 | -------------------------------------------------------------------------------- /stealth/stealth/ipcmode.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | bool Stealth::ipcMode() 4 | { 5 | if (not d_options.ipc()) 6 | return false; 7 | 8 | int fd; 9 | LocalClientSocket uds; 10 | 11 | try 12 | { 13 | uds.open(d_options.unixDomainSocket()); 14 | fd = uds.connect(); 15 | } 16 | catch (...) 17 | { 18 | throw Exception() << "can't connect to `" << 19 | d_options.unixDomainSocket() << '\''; 20 | } 21 | 22 | OFdStream out(fd); 23 | out << d_options.mode() << endl; // send the requested mode 24 | 25 | IFdStream in(fd); 26 | string answer; // wait for the answer 27 | getline(in, answer); 28 | 29 | if (not answer.empty()) // show the answer if something 30 | throw Exception() << answer; // went wrong. 31 | 32 | return true; 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /stealth/icmake/precompileheaders: -------------------------------------------------------------------------------- 1 | string g_compiler; 2 | int g_gch = 1; 3 | 4 | void _precompile(string class) 5 | { 6 | string classIH; 7 | 8 | classIH = class + ".ih"; 9 | if (classIH younger class + ".ih.gch") 10 | run(g_compiler + " -x c++-header " + classIH); 11 | } 12 | 13 | void precompileHeaders() 14 | { 15 | int idx; 16 | list classes; 17 | string class; 18 | 19 | if (!g_gch) 20 | return; 21 | 22 | classes = makelist(O_SUBDIR, "*"); 23 | 24 | 25 | g_compiler = setOpt(CXX, "CXX") + " " + 26 | setOpt(CXXFLAGS, "CXXFLAGS") + " "; 27 | 28 | 29 | _precompile("main"); // precompile the main program .ih file 30 | 31 | 32 | for (idx = listlen(classes); idx--; ) 33 | { 34 | class = classes[idx]; 35 | 36 | chdir(class); 37 | 38 | _precompile(class); 39 | 40 | chdir(g_cwd); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /stealth/documentation/manual/policy/label.yo: -------------------------------------------------------------------------------- 1 | The following bf(LABEL) commands are available: 2 | itemization( 3 | it() bf(LABEL) tt(text) 4 | 5 | This defines a text-label which is written to the bf(REPORT) file, 6 | just before the output generated by the next bf(CHECK)-command. If the next 7 | bf(CHECK)-command generates no output, the label is not written to the 8 | bf(REPORT)-file. Once a bf(LABEL) has been defined, it is used until it is 9 | redefined by the next bf(LABEL) command. Use an empty bf(LABEL) command to 10 | suppress printing labels. 11 | 12 | The text may contain tt(\n) characters (two characters) which are 13 | transformed to a newline character. 14 | it() bf(LABEL) 15 | 16 | As noted, this clears a previously defined tt(LABEL) command. 17 | ) 18 | 19 | Examples: 20 | verb( 21 | LABEL Inspecting files in /etc\nIncluding subdirectories 22 | LABEL) 23 | The latter bf(LABEL) command clears the text of the former bf(LABEL) 24 | command. 25 | -------------------------------------------------------------------------------- /stealth/report/sendmail.cc: -------------------------------------------------------------------------------- 1 | #include "report.ih" 2 | 3 | void Report::sendMail() 4 | { 5 | m3 << "Mailing new logs using: " << 6 | d_policyFile["MAILER"] << ' ' << 7 | d_policyFile["MAILARGS"] << " " << 8 | d_policyFile["EMAIL"] << endl; 9 | 10 | // mailcommand subject and email are called as separate arguments 11 | // If subject contains blanks, they will be interpreted as separate 12 | // arguments by the `mail' IOFork. Usually d_policyFile["MAILER"] will 13 | // call a script. 14 | 15 | Process mail( 16 | Process::CIN | Process::IGNORE_COUT | Process::IGNORE_CERR, 17 | d_policyFile["MAILER"] + ' ' + 18 | d_policyFile["MAILARGS"] + ' ' + 19 | d_policyFile["EMAIL"] 20 | ); 21 | 22 | mail.start(); 23 | 24 | mail << d_headerLine << '\n'; 25 | 26 | rewind(); 27 | 28 | string line; 29 | while (std::getline(*this, line)) 30 | mail << line << '\n'; 31 | 32 | mail.close(); 33 | mail.waitForChild(); 34 | } 35 | -------------------------------------------------------------------------------- /stealth/stealth/jobshandler.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::jobsHandler() 4 | { 5 | bool prompt = not d_options.daemon() && d_options.repeat(); 6 | bool runOnce = not d_options.daemon() && not d_options.repeat(); 7 | 8 | if (prompt) 9 | { 10 | thread(startThread, &Stealth::waitForKey, this).detach(); 11 | cout << "? " << flush; 12 | } 13 | 14 | while (true) 15 | { 16 | nextJob(); 17 | 18 | m1 << d_task << " next." << endl; 19 | 20 | // process the current request 21 | (this->*(s_task.find(d_task.mode())->second))(); 22 | 23 | d_report->mail(); 24 | 25 | if (runOnce) 26 | break; 27 | 28 | if (d_task.hasMode(TERMINATE)) 29 | { 30 | d_ipc.notify(); 31 | break; 32 | } 33 | 34 | if (d_autoJob) 35 | { 36 | d_autoJob = false; 37 | continue; 38 | } 39 | d_ipc.notify(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /stealth/integrityscanner/docheckcommand.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | bool IntegrityScanner::doCHECKcommand(Process &child) 4 | { 5 | removeLOG(); // remove optional 'LOG =' 6 | 7 | string logfile = s_firstWord[1]; // CHECK keywords are followed by 8 | // the name of a logfile 9 | 10 | s_firstWord.match(s_firstWord[3]); // redefine s_firstWord: 1st word 11 | // removed 12 | 13 | if (not isdigit(s_firstWord[1][0])) 14 | d_pathOffset = numeric_limits::max(); 15 | else 16 | { 17 | d_pathOffset = stoul(s_firstWord[1]); 18 | s_firstWord.match(s_firstWord[3]); 19 | } 20 | 21 | nextCommand(child, s_firstWord[0]); // otherwise run the command 22 | 23 | child << flush; 24 | // and return whether there are any 25 | // differences. 26 | return sameOutput(logfile, child); 27 | } 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /stealth/integrityscanner/removelog.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::removeLOG() 4 | { 5 | string matched = s_firstWord[0]; // complete matched text 6 | 7 | if (matched.find("LOG") == 0) // LOG at the beginning 8 | { 9 | size_t pos = matched.find_first_not_of(" \t", 3); 10 | 11 | // got '=', so we got 'LOG =' 12 | // remove 'LOG =' and proceed. 13 | if (pos != string::npos && matched[pos] == '=') 14 | { 15 | m3 << "removed `LOG =', kept `" << 16 | matched.substr(pos + 1) << '\'' << endl; 17 | s_firstWord.match(matched.substr(pos + 1)); 18 | } 19 | else 20 | m3 << "LOG is (partial) logname in `" << matched << '\'' << 21 | endl; 22 | } 23 | else 24 | m3 << "No `LOG =' specified in CHECK command `" << matched << "'" << 25 | endl; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /stealth/options/setmode.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setMode() 4 | { 5 | if ((d_reload = d_arg.option(0, "reload"))) 6 | d_mode = RELOAD; 7 | 8 | if ((d_rerun = d_arg.option(0, "rerun"))) 9 | d_mode = RERUN; 10 | 11 | if ((d_terminate = d_arg.option(0, "terminate"))) 12 | d_mode = TERMINATE; 13 | 14 | if ((d_ping = d_arg.option(0, "ping"))) 15 | d_mode = PING; 16 | 17 | if ((d_suspend = d_arg.option(0, "suspend"))) 18 | d_mode = SUSPEND; 19 | 20 | if ((d_resume = d_arg.option(0, "resume"))) 21 | d_mode = RESUME; 22 | 23 | if ( 24 | (d_daemon = d_arg.option(&d_unixDomainSocket, 'd')) 25 | && 26 | (d_arg.nArgs() == 0) 27 | ) 28 | fmsg << "--daemon: missing Unix Domain File or policy file" << noidl; 29 | 30 | d_ipc = d_ping || d_reload || d_rerun || d_suspend || d_resume || 31 | d_terminate; 32 | 33 | if (d_ipc) 34 | d_unixDomainSocket = d_arg[0]; 35 | 36 | d_foreground = not d_ipc and not d_daemon; 37 | } 38 | -------------------------------------------------------------------------------- /stealth/icmake/loginstall: -------------------------------------------------------------------------------- 1 | // source and dest, absolute or reachable from g_cwd, should exist. 2 | // files and links in source matching dest (if empty: all) are copied to dest 3 | // and are logged in g_log 4 | 5 | // Before they are logged, dest is created 6 | 7 | void logInstall(string src, string pattern, string dest) 8 | { 9 | list entries; 10 | int idx; 11 | 12 | chdir(g_cwd); 13 | 14 | md(dest); 15 | src += "/"; 16 | dest += "/"; 17 | 18 | if (listlen(makelist(O_DIR, src)) == 0) 19 | { 20 | printf("Warning: ", src, " not found: can't install ", src, pattern, 21 | " at ", dest, "\n"); 22 | return; 23 | } 24 | 25 | entries = findAll("f", src, pattern); 26 | 27 | for (idx = listlen(entries); idx--; ) 28 | run("cp " + src + entries[idx] + " " + dest); 29 | 30 | chdir(g_cwd); 31 | entries = findAll("l", src, pattern); 32 | 33 | for (idx = listlen(entries); idx--; ) 34 | run("cp " CPOPTS " " + src + entries[idx] + " " + dest); 35 | } 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /stealth/stealthenums/stealthenums.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_STEALTHENUMS_ 2 | #define INCLUDED_STEALTHENUMS_ 3 | 4 | #include 5 | 6 | struct StealthEnums 7 | { 8 | enum Mode // uses bit-flags values 9 | { 10 | INTEGRITY_SCAN = 1 << 1, // perform an integrity scan 11 | 12 | RERUN = 1 << 4, // rerun on request at WAITING 13 | 14 | SUSPEND = 1 << 2, // suspend a stealth run 15 | 16 | RESUME = 1 << 5, // resume at WAITING 17 | 18 | RELOAD = 1 << 6, // reload the config files 19 | 20 | TERMINATE = 1 << 7, // terminate a Stealth run 21 | 22 | PING = 1 << 8, // ping a daemon 23 | 24 | UNKNOWN = 1 << 9, 25 | }; 26 | }; 27 | 28 | inline constexpr StealthEnums::Mode operator|( 29 | StealthEnums::Mode lhs, StealthEnums::Mode rhs) 30 | { 31 | return static_cast( 32 | static_cast(lhs) | static_cast(rhs) 33 | ); 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/newrunsame.yo: -------------------------------------------------------------------------------- 1 | When s() is subsequently run, it updates its report files under 2 | tt(root/stealth/client). If nothing has changed, the log-files remain 3 | unaltered. Subsequent runs will, however, add some new info to the file 4 | tt(/root/client/report): 5 | verb( 6 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:10:56 +0100 7 | 8 | Check the client's sha1sum program 9 | Initialized report on local/sha1 10 | 11 | checking the client's /usr/bin/find program 12 | Initialized report on remote/binfind 13 | 14 | suid/sgid/executable files uid or gid root on the / partition 15 | Initialized report on remote/setuidgid 16 | 17 | configuration files under /etc 18 | Initialized report on remote/etcfiles 19 | 20 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:22:15 +0100) 21 | Note that just one extra line was added: a timestamp showing the date/time 22 | of the last run. The systems administrator may rotate the report file every 23 | once in a while to reclaim some disk space. 24 | -------------------------------------------------------------------------------- /stealth/integrityscanner/execute.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // receives the next command to execute 4 | void IntegrityScanner::execute(string const &cmd) 5 | { 6 | if (!(s_firstWord << cmd)) // determine first word and the rest 7 | fmsg << "Corrupt line in policy file: " << cmd << noidl; 8 | else 9 | m1 << cmd << endl; 10 | 11 | if (s_firstWord[1] == "LABEL") // set a label 12 | { 13 | d_label = s_firstWord[3]; // the text beyond the LABEL keyword 14 | replace(d_label, // change \\n into newlines 15 | "\\n", "\n"); 16 | } 17 | else if (s_firstWord[1] == "LOCAL") // run a local command 18 | local(s_firstWord[3]); 19 | else if (s_firstWord[1] == "GET") // get a file from the client 20 | get(cmd); 21 | else if (s_firstWord[1] == "PUT") // put a file to the client 22 | put(cmd); 23 | else // or run a remote command 24 | remote(cmd); 25 | } 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /stealth/stealth/reload.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::reload() 4 | { 5 | timestamp("reloads its policy file"); 6 | 7 | if (d_options.dryrun()) 8 | *d_report << "--dry-run: would have reloaded the policy file" << endl; 9 | else 10 | { 11 | PolicyFile *policyFilePtr = new PolicyFile(d_options); 12 | 13 | Report *reportPtr = new Report(d_options, *policyFilePtr); 14 | 15 | d_integrityScanner.reset( 16 | new IntegrityScanner(d_pending, d_options, 17 | *policyFilePtr, *reportPtr) 18 | ); 19 | 20 | d_integrityScanner->startCommandShells(); 21 | 22 | setupFatalReport(); 23 | 24 | d_logUnit.setupLogs(d_logReport); 25 | 26 | d_report.reset(reportPtr); 27 | d_policyFile.reset(policyFilePtr); 28 | 29 | m2 << "reloaded policy file `" << d_options.policyFilePath() << "'\n" 30 | "reconstructed the Integrity Scanner" << endl; 31 | m3 << "max. download size: " << d_options.maxSizeStr() << endl; 32 | } 33 | autoScan("reload"); 34 | } 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /stealth/integrityscanner/startcommandshells.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::startCommandShells() 4 | { 5 | d_sshFork.start(); // start the ssh connection 6 | d_shFork.start(); // start the sh-connection to the localhost 7 | 8 | // try to echo a sentinel by having 9 | // the ssh connection echo it 10 | m3 << "Inserting " << d_sentinel << " into " << d_policyFile["SSH"] << 11 | endl; 12 | 13 | d_sshFork << "/bin/echo \"" << d_sentinel << "\"" << endl; // must flush 14 | 15 | m3 << "Waiting for " << d_sentinel << " from " << d_policyFile["SSH"] << 16 | endl; 17 | 18 | d_testExitValue = false; 19 | waitForSentinel(d_sshFork); // continue after reading 20 | 21 | m3 << d_policyFile["SSH"] << " appears to be functioning well" << endl; 22 | 23 | if (d_options.verbosity() != 3) 24 | m2 << "Integrity Scanner command shells activated" << endl; 25 | } 26 | -------------------------------------------------------------------------------- /stealth/icmake/logzip: -------------------------------------------------------------------------------- 1 | // names may be a series of files in src, not a wildcard. 2 | // if it's empty then all files in src are used. 3 | // the files are gzipped and logged in dest. 4 | // src and dest do not have to end in / 5 | 6 | void logZip(string src, string names, string dest) 7 | { 8 | list files; 9 | int idx; 10 | string file; 11 | 12 | chdir(g_cwd); 13 | 14 | md(dest); 15 | dest += "/"; 16 | 17 | if (src != "") 18 | { 19 | if (listlen(makelist(O_DIR, src)) == 0) 20 | { 21 | printf("Warning: ", src, " not found: can't install ", src, names, 22 | " at ", dest, "\n"); 23 | return; 24 | } 25 | chdir(src); 26 | } 27 | 28 | if (names == "") 29 | files = makelist("*"); 30 | else 31 | files = strtok(names, " "); 32 | 33 | for (idx = listlen(files); idx--; ) 34 | { 35 | file = files[idx]; 36 | run("gzip -n -9 < " + file + " > " + file + ".gz"); 37 | } 38 | 39 | run("tar cf - *.gz | (cd " + g_cwd + "; cd " + dest + "; tar xf -)"); 40 | 41 | run("rm *.gz"); 42 | } 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/logrotate.yo: -------------------------------------------------------------------------------- 1 | A program like bf(logrotate)(1) allows its users to specify a command or 2 | script immediately following log-rotation, and `s() tt(--resume 3 | pidfile)' could be specified nicely in such a post-rotation section. 4 | 5 | Here is an example of a specification that can be used with 6 | bf(logrotate)(1). Logrotate (on Debian systems) keeps its configuration files 7 | in tt(/etc/logrotate.d), and assuming there is a host tt(target), whose report 8 | file is tt(/var/stealth/target/report), the required bf(logrotate)(1) 9 | specification file (e.g., tt(/etc/logrotate.d/target)) could be: 10 | verbinclude(../../../share/etc/logrotate.d/target) 11 | Using this specification file, bf(logrotate)(1) will 12 | itemization( 13 | it() perform weekly rotations of the report file; 14 | it() keep up to 12 rotated files, compressing them using bf(gzip)(1); 15 | it() suspend the s() daemon, before rotating its report file; 16 | suspended; 17 | it() following the rotation, s()'s actions are resumed. 18 | ) 19 | Note thet tt(stealth --resume xxx) always initiates another file integrity 20 | scan. 21 | -------------------------------------------------------------------------------- /stealth/integrityscanner/skipdecision.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // line: lines like 4 | // < 9fd210eed1190870f69c9bc7544cfacb82099efd /root/aantekeningen 5 | // so: 6 | // /root/aantekeningen 7 | // toSkip: a line from the `skipfiles' file 8 | // Files are skipped if 'line' contains `toSkip' and: 9 | // 1. toSkip ends in '/' 10 | // or 11 | // 2. the line ends after 'toSkip' or after 'toSkip' 12 | // or 13 | // 3. the character on 'line' after 'toSkip' is a blank space 14 | 15 | 16 | bool IntegrityScanner::skipDecision(string &path, string const &skipPath) const 17 | { 18 | if (path.find(skipPath) != 0) // skipPath not in path 19 | return false; 20 | 21 | if 22 | ( // SKIP this entry, IF: 23 | skipPath.back() == '/' // skipPath ends in '/' 24 | || // or 25 | path == skipPath // path equals skipPath 26 | ) 27 | { 28 | path = skipPath; // replace path by skipPath 29 | return true; 30 | } 31 | 32 | return false; // else don't skip this entry 33 | } 34 | 35 | -------------------------------------------------------------------------------- /stealth/integrityscanner/local.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | /* 4 | At this point: LOCAL was seen. Beyond that, we must see: 5 | 6 | NOTEST CHECK ... 7 | CHECK ... 8 | NOTEST ... 9 | ... 10 | 11 | NOTEST means the return value of the command is not tested 12 | CHECK means that the output is compared with a former log 13 | */ 14 | 15 | void IntegrityScanner::local(string const &s_firstWord2) 16 | { 17 | s_firstWord.match(s_firstWord2); // what's beyond `LOCAL' ? 18 | 19 | // set d_testExitValue 20 | d_testExitValue = !removeFirstWord("NOTEST"); // according to !NOTEST 21 | 22 | if (removeFirstWord("CHECK")) // ... CHECK ... 23 | { 24 | if (!doCHECKcommand(d_shFork)) // so, do the command 25 | d_report << "\n" // and check the result 26 | "*** BE CAREFUL *** REMAINING RESULTS MAY BE FORGED\n" << 27 | endl; 28 | } 29 | else 30 | doPlainCommand(d_shFork); // do unchecked command 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/rsyslog.yo: -------------------------------------------------------------------------------- 1 | When using bf(rsyslogd)(1) property based filters may be used to filter 2 | syslog messages and write them to a file of your choice. E.g., to filter 3 | messages starting with the syslog message tag (e.g., tt(STEALTH)) use 4 | verb( 5 | :syslogtag, isequal, "STEALTH:" /var/log/stealth.log 6 | :syslogtag, isequal, "STEALTH:" stop 7 | ) 8 | Note that the colon is part of the tag, but is not specified with the 9 | tt(syslog-tag) option. 10 | 11 | This causes all messages having the tt(STEALTH:) tag to be written on 12 | tt(/var/log/stealth.log) after which they are discarded. More extensive 13 | filtering is also supported, see, e.g., 14 | tt(http://www.rsyslog.com/doc/rsyslog_conf_filter.html) and 15 | tt(http://www.rsyslog.com/doc/property_replacer.html) 16 | 17 | Time stamps written by tt(rsyslogd) are not controlled by s()'s 18 | tt(--time-stamp) option, but, e.g., by a tt(TZ) specification in 19 | tt(/etc/default/rsyslog). Simply add the line 20 | verb( export TZ=UTC) 21 | to tt(/etc/default/rsyslog), followed by restarting tt(rsyslogd) configures 22 | tt(rsyslogd) to generate time stamps using UTC. 23 | -------------------------------------------------------------------------------- /stealth/policyfile/directivesandcommands.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::directivesAndCommands() 4 | try 5 | { 6 | ConfigFile configfile(d_options.policyFilePath()); 7 | 8 | for (size_t idx = 0, size = configfile.size(); idx != size; ++idx) 9 | { 10 | string line = configfile[idx]; 11 | 12 | if (line == "%%") 13 | { 14 | loadOptions(configfile, idx + 1); 15 | return; 16 | } 17 | 18 | if (!(s_firstWord << line)) // can't match a first word 19 | { 20 | if (!(s_comment << line)) 21 | wmsg << "Ignored unrecognized line `" << line << '\'' << endl; 22 | continue; 23 | } 24 | 25 | if (s_firstWord[1] == "USE") 26 | insert(d_use, line); 27 | else if (s_firstWord[1] == "DEFINE") 28 | insert(d_define, line); 29 | else 30 | { 31 | mp << "Regular command: `" << line << '\'' << endl; 32 | d_command.push_back(line); 33 | } 34 | } 35 | } 36 | catch (exception const &exc) 37 | { 38 | fmsg << exc.what() << noidl; 39 | } 40 | -------------------------------------------------------------------------------- /stealth/stealth/data.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | FBB::LinearMap Stealth::s_task = 4 | { 5 | {RELOAD, &Stealth::reload}, // autoscan 6 | {TERMINATE, &Stealth::terminate}, // terminates 7 | {INTEGRITY_SCAN, &Stealth::integrityScan}, 8 | {SUSPEND, &Stealth::suspend}, 9 | {RESUME, &Stealth::resume}, // autoscan 10 | {RERUN, &Stealth::rerun}, // autoscan 11 | }; 12 | 13 | // possible incoming requests at the ipcInterface 14 | FBB::LinearMap Stealth::s_request = 15 | { 16 | {INTEGRITY_SCAN, &Stealth::unknownRequest}, 17 | 18 | {PING, &Stealth::pingRequest}, 19 | {RERUN, &Stealth::rerunRequest}, 20 | {SUSPEND, &Stealth::suspendRequest}, 21 | {RESUME, &Stealth::resumeRequest}, 22 | {RELOAD, &Stealth::reloadRequest}, 23 | {TERMINATE, &Stealth::terminateRequest}, 24 | 25 | {UNKNOWN, &Stealth::unknownRequest}, 26 | }; 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /stealth/icmconf2: -------------------------------------------------------------------------------- 1 | // This icmconf file is used for compiling class-specific libraries in 2 | // sub-directories. 3 | 4 | #define USE_ECHO ON 5 | #define CLS 6 | 7 | #ifndef THREAD 8 | #define THREAD "" 9 | #endif 10 | 11 | //#define CXX "g++" 12 | #define CXX "g++-5" 13 | 14 | #define CXXFLAGS "--std=c++14 " ${THREAD} " -Wall -O2" 15 | #define SOURCES "*.cc" 16 | #define TMP_DIR "tmp" 17 | #define OBJ_EXT ".o" 18 | #define DEFCOM "library" 19 | 20 | //////////////////////////////////////////////////////////////////////////// 21 | #define ADD_LIBRARIES "" 22 | #define ADD_LIBRARY_PATHS "" 23 | #define LDFLAGS "" 24 | #define MAIN "" 25 | #define PARSER_DIR "" 26 | #define PARSFLAGS "" 27 | #define PARSGEN "" 28 | #define PARSOUT "" 29 | #define PARSSPEC "" 30 | #define SCANFLAGS "" 31 | #define SCANGEN "" 32 | #define SCANNER_DIR "" 33 | #define SCANOUT "" 34 | #define SCANSPEC "" 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /stealth/stealth/stealth.ih: -------------------------------------------------------------------------------- 1 | #include "stealth.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../policyfile/policyfile.h" 18 | #include "../integrityscanner/integrityscanner.h" 19 | #include "../report/report.h" 20 | #include "../msg/msg.h" 21 | #include "../util/util.h" 22 | 23 | 24 | inline void Stealth::timestamp(char const *label) 25 | { 26 | d_report->timestamp(label, d_integrityScanner->nScans()); 27 | } 28 | 29 | inline void Stealth::startThread(void (Stealth::*member)(), Stealth *obj) 30 | { 31 | (obj->*member)(); 32 | } 33 | 34 | using namespace std; 35 | using namespace FBB; 36 | 37 | class LogReportbuf: public streambuf 38 | { 39 | Report &d_report; 40 | 41 | public: 42 | LogReportbuf(Report &report); 43 | 44 | private: 45 | int overflow(int ch) override; 46 | int sync() override; 47 | }; 48 | -------------------------------------------------------------------------------- /stealth/options/setdownloadsize.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::setDownloadSize() 4 | { 5 | if (not d_arg.option(&d_maxSizeStr, "max-size")) 6 | return; 7 | 8 | if (d_ipc) 9 | fmsg << "--max-size incompatible with IPC calls" << noidl; 10 | 11 | size_t pos; 12 | try 13 | { 14 | d_maxDownloadSize = stoull(d_maxSizeStr, &pos); 15 | 16 | switch (int ch = toupper(d_maxSizeStr[pos])) 17 | { 18 | case 'G': 19 | d_maxDownloadSize *= 1024; 20 | // FALLING THRU 21 | 22 | case 'M': 23 | d_maxDownloadSize *= 1024; 24 | // FALLING THRU 25 | 26 | case 'K': 27 | d_maxDownloadSize *= 1024; 28 | // FALLING THRU 29 | 30 | default: 31 | if (ch == 'B' || pos == d_maxSizeStr.length()) 32 | return; 33 | break; 34 | } 35 | } 36 | catch (...) 37 | {} 38 | 39 | fmsg << "--max-size " << d_maxSizeStr << ": invalid option value" << 40 | noidl; 41 | } 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /stealth/integrityscanner/copy.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // SEE ALSO THE MEMBER waitForSentinel() 4 | 5 | void IntegrityScanner::copy(Process &src, string const &fname) 6 | { 7 | ofstream currentReport(fname.c_str()); 8 | 9 | if (!currentReport) 10 | fmsg << "Can't open `" << fname << "' to write" << noidl; 11 | 12 | m3 << "copy: about to read child input" << endl; 13 | 14 | string line; 15 | off_t length = 0; 16 | 17 | // `line' is the line as produced by the executed command 18 | while (getline(src, line)) 19 | { 20 | checkSize(fname, length += line.length() + 1); // throws if not OK 21 | 22 | m3 << "copy SAW: `" << line << '\'' << endl; 23 | 24 | if (line.find(d_sentinel) == 0) 25 | { 26 | m3 << "GOT Sentinel" << endl; 27 | break; 28 | } 29 | 30 | string path = getPath(line); // extract the path from the line 31 | 32 | if (not (this->*d_skip)(path)) // write `line' to the report, 33 | currentReport << line << '\n'; // unless it can be skipped 34 | } 35 | 36 | testExitValue(src.str(), line); 37 | } 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/checking.yo: -------------------------------------------------------------------------------- 1 | Next, we check the integrity of the received tt(sha1sum) program. For this, we 2 | use the monitor's tt(sha1sum) program: 3 | verb( 4 | LABEL \nCheck the client's sha1sum program 5 | LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum 6 | ) 7 | The tt(LABEL) command writes the label to the report file just before 8 | writing the tt(sha1sum) program's output. 9 | 10 | The tt(LOCAL) command checks the sha1sum of the program copied from the 11 | client. The report is written on the file 12 | tt(/root/stealth/client/local/sha1). If this fails, s() terminates, alerting 13 | tt(admin@elsewhere) that the check failed. This is a serious event, as it 14 | indicates that either the monitor's tt(sha1sum) is behaving unexpectedly or 15 | that the client's tt(sha1sum) program has unexpectedly changed. 16 | 17 | The tt(sha1sum) program em(may) have changed due to a normal upgrade. If 18 | so, tt(admin@elsewhere) will know this, and can (probably) ignore the 19 | warning. The next time s() is run, the (now updated) SHA1 value is used, and 20 | it again compares the obtained tt(SHA1) value to the one obtained for the 21 | downloaded tt(sha1sum) program. 22 | 23 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/failing.yo: -------------------------------------------------------------------------------- 1 | If the client's tt(sha1sum) program itself is altered, a serious situation 2 | has developed. In that case, further actions by s() would be suspect, as their 3 | results might easily be currupted. Additional checks em(will) be performed, 4 | but a warning is generated on the tt(report) file (and in the mail sent to 5 | tt(admin@elsewhere)): 6 | verb( 7 | STEALTH (4.00.00) started at Sat, 07 Feb 2015 22:27:15 +0100 8 | 9 | Check the client's sha1sum program 10 | MODIFIED: /root/tmp/sha1sum 11 | < fc62fc774999584f1e29e0f94279a652 /root/tmp/sha1sum 12 | > 45251e259bfaf1951658a7b66c328c52 /root/tmp/sha1sum 13 | 14 | *** BE CAREFUL *** REMAINING RESULTS MAY BE FORGED 15 | 16 | configuration files under /etc 17 | REMOVED: /etc/motd.org 18 | > 945d0b8208e9861b8f9f2de155e619f9 /etc/motd.org 19 | MODIFIED: /etc/motd 20 | < 945d0b8208e9861b8f9f2de155e619f9 /etc/motd 21 | > 7f96195d5f051375fe7b523d29e379c1 /etc/motd) 22 | (The report shows the removal of the previously added file tt(motd.org), 23 | and the modification of tt(motd). These are real, as the original tt(motd) 24 | file, modified earlier, was restored at this point). 25 | -------------------------------------------------------------------------------- /stealth/documentation/manual/access/login.yo: -------------------------------------------------------------------------------- 1 | When user@monitor now issues, for the first time, the command 2 | verb( ssh account@monitor) 3 | tt(Ssh) responds like this: 4 | verb( The authenticity of host 'monitor (xxx.yyy.aaa.bbb)' can't be 5 | established. 6 | RSA key fingerprint is c4:52:d6:a3:d4:65:0d:5e:2e:66:d8:ab:de:ad:12:be. 7 | Are you sure you want to continue connecting (yes/no)?) 8 | Answering tt(yes) results in the message: 9 | verb( Warning: Permanently added 'monitor,xxx.yyy.aaa.bbb' (RSA) to the 10 | list of known hosts.) 11 | 12 | The next time a login is attempted, the authenticity question is not asked 13 | anyore. However, the proper value of the host's RSA key fingerprint (i.e., the 14 | key fingerprint of the em(client) computer) should em(always) be verified to 15 | prevent em(man in the middle) attacks. The proper value may be obtained at the 16 | client by issuing there the command 17 | verb( ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub) 18 | This should show the same value of the fingerprint as shown when the 19 | first tt(ssh) connection was established. E.g., 20 | verb( 21 | 1024 c4:52:d6:a3:d4:65:0d:5e:2e:66:d8:ab:de:ad:12:be ssh_host_rsa_key.pub) 22 | -------------------------------------------------------------------------------- /stealth/policyfile/fetchcommands.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | // called from PolicyFile() 4 | 5 | void PolicyFile::fetchCommands() 6 | { 7 | directivesAndCommands(); 8 | 9 | string &base = d_use["BASE"]; 10 | 11 | if (base.back() != '/') 12 | base += '/'; 13 | 14 | bool ok = d_use.count("SSH"); 15 | 16 | for(auto &entry: d_define) 17 | replaceDefines(entry.second); 18 | 19 | for(auto &entry: d_use) 20 | replaceDefines(entry.second); 21 | 22 | for(auto &entry: d_command) 23 | replaceDefines(entry); 24 | 25 | fixRelativeLocations(); 26 | 27 | if (size_t parseOnly = d_options.parsePolicy()) 28 | { 29 | if (parseOnly > 1) 30 | { 31 | for(auto &value: d_use) 32 | mp << "USE " << value.first << ": " << value.second << endl; 33 | } 34 | 35 | mp.clear(); 36 | 37 | mp << "REPORT: " << d_use["REPORT"] << endl; 38 | 39 | for (size_t idx = 0; idx != d_command.size(); ++idx) 40 | mp << (idx + 1) << ": " << d_command[idx] << endl; 41 | 42 | throw 0; 43 | } 44 | 45 | if (!ok) 46 | fmsg << "USE SSH ... entry missing in the policy file" << noidl; 47 | } 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /stealth/report/demo/demo.cc: -------------------------------------------------------------------------------- 1 | /* 2 | demo.cc 3 | 4 | g++ demo.cc -L../.. -lstealth | & less 5 | */ 6 | 7 | #include "demo.h" 8 | 9 | int main(int argc, char **argv, char **envp) 10 | { 11 | try 12 | { 13 | Reporter rep("report"); 14 | 15 | rep << Util::date << ": Hello world\n"; 16 | 17 | rep.reset(); 18 | 19 | string s; 20 | 21 | cout << "========= 0 ===========\n"; 22 | 23 | while (getline(rep, s)) 24 | cout << "Added: " << s << "\n"; 25 | 26 | cout << "========= 1 ===========\n"; 27 | 28 | sleep(5); 29 | 30 | rep.reinit(); // make sure we can add new info 31 | // as a new run 32 | 33 | // insert info 34 | rep << Util::date << ": Hello world (2nd time)\n"; 35 | 36 | rep.reset(); // reset the stream to read it again 37 | 38 | while (getline(rep, s)) 39 | cout << "Added: " << s << "\n"; 40 | 41 | cout << "========= 2 ===========\n"; 42 | 43 | return 0; 44 | } 45 | catch(exception const &e) 46 | { 47 | cerr << "Exception " << e.what() << "\n"; 48 | return 1; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /stealth/runmode/runmode.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_RUNMODE_ 2 | #define INCLUDED_RUNMODE_ 3 | 4 | #include 5 | #include 6 | 7 | #include "../stealthenums/stealthenums.h" 8 | 9 | struct RunMode: public StealthEnums 10 | { 11 | friend std::ostream &operator<<(std::ostream &out, RunMode const &mode); 12 | 13 | private: 14 | static FBB::LinearMap const s_modeName; 15 | 16 | volatile Mode d_mode = INTEGRITY_SCAN; 17 | 18 | public: 19 | bool hasMode(Mode query) const; 20 | Mode mode() const; 21 | 22 | void setMode(Mode mode); 23 | 24 | static Mode validate(int mode); 25 | }; 26 | 27 | inline RunMode::Mode RunMode::validate(int mode) 28 | { 29 | return 30 | ((mode - 1) & mode) == 0 31 | && 32 | mode <= UNKNOWN ? 33 | static_cast(mode) 34 | : 35 | UNKNOWN; 36 | } 37 | 38 | inline RunMode::Mode RunMode::mode() const 39 | { 40 | return d_mode; 41 | } 42 | 43 | inline bool RunMode::hasMode(Mode mode) const 44 | { 45 | return d_mode & mode; 46 | } 47 | 48 | inline std::ostream &operator<<(std::ostream &out, RunMode const &mode) 49 | { 50 | return out << RunMode::s_modeName.find(mode.mode())->second; 51 | } 52 | 53 | #endif 54 | 55 | 56 | -------------------------------------------------------------------------------- /stealth/report/report.h: -------------------------------------------------------------------------------- 1 | #ifndef REPORT_H_ 2 | #define REPORT_H_ 3 | 4 | #include 5 | #include 6 | 7 | class Options; 8 | class PolicyFile; 9 | 10 | class Report: public std::fstream 11 | { 12 | std::string d_name; 13 | 14 | Options &d_options; 15 | PolicyFile const &d_policyFile; 16 | 17 | std::ios::pos_type d_startSize; 18 | std::ios::pos_type d_beginMail; 19 | 20 | std::string d_headerLine; 21 | 22 | public: 23 | Report(Options &options, PolicyFile const &policyFile); 24 | ~Report(); 25 | 26 | Report(Report const &other) = delete; 27 | Report &operator=(Report const &other) = delete; 28 | 29 | void timestamp(char const *label, size_t nScans); 30 | void mail(); 31 | void scanHeader(); // writes the integrity scan header, 32 | // initializes d_beginMail 33 | private: 34 | void rewind(); // prepare for reading 35 | void processMail(); 36 | void sendMail(); 37 | void refresh(); // set d_beginMail to the log's EOF pos. 38 | bool hasMail(); // true if there is info beyond 39 | // d_beginMail 40 | 41 | std::ios::pos_type endpos(); 42 | }; 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/use.yo: -------------------------------------------------------------------------------- 1 | Next some tt(USE) directives, matching our specific, local, 2 | situation, are defined: 3 | verb( 4 | USE BASE /root/stealth/client 5 | USE EMAIL admin@elswhere 6 | USE MAILER /root/bin/stealthmail 7 | USE MAILARGS "Client STEALTH report" 8 | USE SSH ${SSHCMD}) 9 | 10 | itemization( 11 | it() All output is written under the tt(/root/stealth/client) directory; 12 | it() Mail is sent to the user tt(admin@elsewhere); 13 | it() As mail program we use a filtering script (tt(stealthmail)), which is 14 | installed in tt(/root/bin); 15 | it() The script handles its own argument. As it can be used by s() 16 | performing integrity scans on other clients as well, it is given an 17 | argument which can be used as e-mail subject, identifying the 18 | client-computer that has been integrity-scanned; 19 | it() The ssh-command is defined by the tt(SSHCMD). It's definition is used 20 | at the tt(USE SSH) specification; 21 | it() Default values of all remaining tt(USE) directives are OK, and thus 22 | were not explicitly specified. They are: 23 | verb( USE DD /bin/dd 24 | USE DIFF /usr/bin/diff 25 | USE REPORT report 26 | USE SH /bin/sh) 27 | ) 28 | -------------------------------------------------------------------------------- /stealth/policyfile/replacedefines.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | void PolicyFile::replaceDefines(string &text) 4 | { 5 | // Pattern define("(\\$\\{([a-zA-Z0-9_]+)\\})"); // [0]: all text, 6 | // // [1]: all ${NAME} text 7 | // // [2]: NAME itself 8 | 9 | mp << "PolicyFile::replaceDefines in " << text << endl; 10 | 11 | string out; 12 | 13 | while (s_define << text) // Got a ${NAME} 14 | { 15 | out += s_define.before(); // Get all before ${NAME} 16 | 17 | out += // Add: 18 | hasDEFINE(s_define[2]) ? // if NAME is DEFINEd 19 | getDEFINE(s_define[2]) // then its definition 20 | : // otherwise 21 | s_define.matched(); // ${NAME} (unmodified) 22 | 23 | mp << " step: " << out << endl; 24 | 25 | text = s_define.beyond(); // remove all matched 26 | } // text from `text' 27 | 28 | mp << "PolicyFile::replaceDefines -> " << text << endl; 29 | 30 | text = out + text; // redefine `text' 31 | } 32 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/policy.demo: -------------------------------------------------------------------------------- 1 | DEFINE SSHCMD /usr/bin/ssh root@client -T -q exec /bin/bash --noprofile 2 | DEFINE EXECSHA1 -xdev -perm +u+s,g+s \( -user root -or -group root \) \ 3 | -type f -exec /usr/bin/sha1sum {} \; 4 | 5 | USE BASE /root/stealth/client 6 | USE EMAIL admin@elswhere 7 | USE MAILER /root/bin/stealthmail 8 | USE MAILARGS "Client STEALTH report" 9 | USE SSH ${SSHCMD} 10 | 11 | USE DD /bin/dd 12 | USE DIFF /usr/bin/diff 13 | USE REPORT report 14 | USE SH /bin/sh 15 | 16 | GET /usr/bin/sha1sum /root/tmp 17 | 18 | LABEL \nCheck the client's sha1sum program 19 | LOCAL CHECK LOG = local/sha1 /usr/bin/sha1sum /root/tmp/sha1sum 20 | 21 | LABEL \nchecking the client's /usr/bin/find program 22 | CHECK LOG = remote/binfind /usr/bin/sha1sum /usr/bin/find 23 | 24 | LABEL \nsuid/sgid/executable files uid or gid root on the / partition 25 | CHECK LOG = remote/setuidgid /usr/bin/find / ${EXECSHA1} 26 | 27 | LABEL \nconfiguration files under /etc 28 | CHECK LOG = remote/etcfiles \ 29 | /usr/bin/find /etc -type f -not -perm /6111 \ 30 | -not -regex "/etc/\(adjtime\|mtab\)" \ 31 | -exec /usr/bin/sha1sum {} \; 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /stealth/integrityscanner/run.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | void IntegrityScanner::run() 4 | { 5 | d_active = true; 6 | 7 | ++d_nScans; 8 | 9 | setSentinel(); // determine d_sentinel 10 | 11 | d_cmdIterator = d_policyFile.firstCmd(); // d_cmdIterator is set to 12 | // the first command. It's a 13 | // true iterator, so we can 14 | // add values to it, below. 15 | 16 | if (size_t cmdNr = d_options.commandNr()) // is there a command number? 17 | foreground(cmdNr); // run it in the foreground 18 | else // no number: process all 19 | { // commands 20 | auto beyond = d_policyFile.beyondCmd(); 21 | 22 | for (auto &cmd: ranger(d_cmdIterator, beyond)) 23 | { 24 | if (d_pending.hasMode(SUSPEND | RELOAD | TERMINATE)) 25 | { 26 | m1 << "integrity scan interrupted by " << 27 | d_pending << " request" << endl; 28 | d_active = false; 29 | } 30 | execute(cmd); 31 | } 32 | } 33 | 34 | m3 << "policy file processed" << endl; 35 | d_active = false; 36 | } 37 | -------------------------------------------------------------------------------- /stealth/stealth/nextjob.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | void Stealth::nextJob() 4 | { 5 | if (not d_options.repeat()) // if the scan is not automatically 6 | d_job.wait(); // restarted, then wait for the next job 7 | else 8 | { 9 | size_t nSeconds = d_options.nextIntegrityScan(); 10 | 11 | m2 << "waiting for " << nSeconds << " seconds or for a command" << 12 | endl; 13 | 14 | while (true) 15 | { 16 | auto cvStatus = d_job.wait_for(chrono::seconds(nSeconds)); 17 | 18 | m2 << "wait ends" << endl; 19 | 20 | if (cvStatus != cv_status::timeout) 21 | break; 22 | 23 | m2 << "timeout" << endl; 24 | 25 | if 26 | ( 27 | d_task.hasMode(SUSPEND) // At timeout during 28 | || // suspend, or 29 | d_integrityScanner->active() // still busy scanning 30 | ) 31 | { 32 | m2 << "SUSPEND or actively scanning: wait some more" << endl; 33 | continue; // then wait some more 34 | } 35 | 36 | d_task.setMode(INTEGRITY_SCAN); 37 | d_autoJob = true; 38 | break; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /stealth/share/usr/bin/stealthcron: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PROG=`basename $0` 4 | STEALTH=/usr/bin/stealth 5 | 6 | testAbsolute() 7 | { 8 | echo $1 | grep "^/" > /dev/null 2>&1 && return 9 | 10 | echo "\`$1' must be absolute path" 11 | exit 1 12 | } 13 | 14 | case $# in 15 | (2|3) 16 | testAbsolute $1 17 | testAbsolute $2 18 | if [ "$3" != "" ] 19 | then 20 | testAbsolute $3 21 | SKIP="-s $3" 22 | fi 23 | 24 | if [ -x ${STEALTH} ] ; then 25 | ${STEALTH} --ping $1 26 | if [ $? -ne 0 ] ; then 27 | /usr/bin/logger -t STEALTHCRON -p daemon.warning -- \ 28 | restarting stealth --daemon $1 ... 29 | rm -f $1 30 | ${STEALTH} --daemon $1 ${SKIP} $2 31 | fi 32 | fi 33 | ;; 34 | 35 | (*) 36 | echo " 37 | $PROG by Frank B. Brokken (f.b.brokken@rug.nl) 38 | Usage: $PROG uds policyfile [skipfile] 39 | where: 40 | uds: absolute path to the Unix Domain Socket to be used 41 | policyfile: absolute path to the policyfile to be used 42 | skipfile: absolute path to the skipfile to be used (optional) 43 | 44 | calls $STEALTH} --ping uds. 45 | If that fails, 46 | ${STEALTH} --daemon uds policyfile 47 | or (if skipfile was specified) 48 | ${STEALTH} --daemon uds policyfile -s skipfile policyfile 49 | is started. 50 | " 51 | exit 1 52 | ;; 53 | esac 54 | -------------------------------------------------------------------------------- /stealth/integrityscanner/sameoutput.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | bool IntegrityScanner::sameOutput(string const &logfile, Process &extractor) 4 | { 5 | string current = logfile + ".cur"; // create current logfile 6 | 7 | if (!Util::mkdir(current)) // make sure directory exists 8 | fmsg << "unable to create the logfile `" << current << '\'' << noidl; 9 | 10 | m3 << "logs to " << current << endl; 11 | 12 | copy(extractor, current); // copy the info in extractor 13 | // to the current logfile 14 | 15 | if (access(logfile.c_str(), R_OK) != 0) // no old report yet 16 | { 17 | m3 << "writing new report: " << logfile << '\n'; 18 | 19 | rename(current.c_str(), logfile.c_str()); // install `logfile' 20 | 21 | if (d_label.length()) 22 | d_report << d_label << endl; 23 | 24 | d_report << "Initialized report on " << logfile << endl; 25 | 26 | m3 << "initialized report on " << logfile << endl; 27 | return true; 28 | } 29 | 30 | m3 << "comparing new integrity scan results to: `" << logfile << '\'' << 31 | endl; 32 | 33 | return noDifferences(current, logfile); // return true if there aren't any 34 | // differences. 35 | } 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /stealth/logunit/setuplogs1.cc: -------------------------------------------------------------------------------- 1 | #include "logunit.ih" 2 | 3 | // If --log was requested, define the logbuffer. 4 | // If --syslog was requested define the syslogbuf 5 | // If either fails, send fmsg. 6 | // 7 | // If both succeed messages inserted into imsg (and so: into m1..m3) are sent 8 | // to all logfiles; if --stdout has also been specified then imsg also inserts 9 | // into cout. 10 | // 11 | // fmsg, after setuplogs also inserts into the mail, and pending mail is 12 | // delivered when the mail object is destroyed. 13 | 14 | void LogUnit::setupLogs() 15 | { 16 | unique_ptr log(newLog()); 17 | 18 | unique_ptr syslog(newSyslogStream()); 19 | 20 | unique_ptr imsgbuf(new MultiStreambuf); 21 | 22 | if (log.get() != 0) 23 | { 24 | d_log.swap(log); // install the new Log 25 | imsgbuf->insert(*d_log); 26 | } 27 | 28 | if (syslog.get() != 0) 29 | { 30 | d_syslog.swap(syslog); // install the new syslogbuf 31 | imsgbuf->insert(*d_syslog); 32 | } 33 | 34 | if (d_options.stdout()) 35 | imsgbuf->insert(cout); 36 | 37 | if (imsgbuf->begin() != imsgbuf->end()) 38 | { 39 | d_imsgbuf.swap(imsgbuf); 40 | imsg.reset(d_imsgbuf.get()); 41 | } 42 | 43 | unique_ptr fmsgbuf(new MultiStreambuf); 44 | fmsgbuf->insert(imsg); 45 | d_fmsgbuf.swap(fmsgbuf); 46 | 47 | fmsg.reset(d_fmsgbuf.get()); 48 | } 49 | -------------------------------------------------------------------------------- /stealth/icmake/manual: -------------------------------------------------------------------------------- 1 | void manual() 2 | { 3 | list files; 4 | string file; 5 | int idx; 6 | string compiler; 7 | 8 | compiler = setOpt(CXX, "CXX"); 9 | 10 | md("tmp/manual/LaTeX tmp/manual/html tmp/manual/pdf tmp/manual/ps " 11 | "tmp/manual/text"); 12 | 13 | if (!exists("tmp/usage.txt")) 14 | { 15 | run(compiler + 16 | " --std=c++0x -o tmp/usage documentation/manual/usage.cc"); 17 | run("tmp/usage > tmp/usage.txt"); 18 | } 19 | 20 | chdir("documentation/manual"); 21 | 22 | // create the html version of the manual 23 | run("yodl2html -l3 " PROJECT ".yo"); 24 | run("mv *.html ../../tmp/manual/html"); 25 | 26 | // create the LaTex and derived versions of the manual 27 | #define LATEXDEST "../../tmp/manual/LaTeX/stealth.latex" 28 | run("yodl2latex -o " LATEXDEST " stealth.yo"); 29 | 30 | run("cp stealth.sty ../../tmp/manual/LaTeX"); 31 | 32 | chdir("../../tmp/manual/LaTeX"); 33 | runP(P_NOCHECK, "latex stealth.latex"); 34 | runP(P_NOCHECK, "latex stealth.latex"); 35 | run("latex stealth.latex"); 36 | run("rm stealth.aux stealth.log stealth.out stealth.toc"); 37 | 38 | run("dvips -o ../ps/stealth.ps stealth.dvi"); 39 | 40 | chdir("../ps"); 41 | run("ps2pdf stealth.ps ../pdf/stealth.pdf"); 42 | 43 | // create the txt version of the manual 44 | //run("yodl2txt -o " TXTMANUAL " stealth.yo"); 45 | 46 | exit(0); 47 | } 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /stealth/documentation/manual/access/monitor.yo: -------------------------------------------------------------------------------- 1 | The monitor's user calling s() to scan the client must first generate 2 | an tt(ssh-keypair): 3 | verb( ssh-keygen -t rsa) 4 | By default this generates a public/private ssh key-pair in the directory 5 | tt(.ssh) in the user's home directory. The program asks for a 6 | em(passphrase). A passphrase can be defined (in which case it must be proviced 7 | when s() is started) or, if the security if the monitor is sufficiently 8 | guaranteed, it can remain empty. To generate an ssh-key without passphrase 9 | simply press tt(Enter) in response to the question 10 | verb( Enter passphrase (empty for no passphrase):) 11 | (a confirmation is required: just press tt(Enter) again). 12 | 13 | tt(Ssh-keygen) then returns a key fingerprint, e.g., 14 | verb( 03:96:49:63:8a:64:33:45:79:ab:ca:de:c8:c8:4f:e9 user@monitor) 15 | which may be saved for future reference. 16 | 17 | In the user's tt(.ssh) directory the files tt(id_rsa) and tt(id_rsa.pub) 18 | are now created, which completes the preparations at the monitor. 19 | 20 | If, instead of running s() in daemon mode it is preferred to let s() perform 21 | single, but automated integrity scans, then new bf(ssh)(1) connections may be 22 | difficult to establish if the used ssh-key is passphrase-protected. To 23 | implement this scenario (i.e., automated integrity scans using passphrase 24 | protected ssh-keys) the program bf(ssh-cron)(1) can profitably be used. 25 | 26 | -------------------------------------------------------------------------------- /stealth/integrityscanner/get.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // Command forms: 4 | // GET remote-file local-file 5 | // GET NOTEST remote-file local-file 6 | 7 | void IntegrityScanner::get(string const &cmd) 8 | { 9 | removeFirstWord("GET"); // strip off `GET' 10 | 11 | d_testExitValue = !removeFirstWord("NOTEST"); // [NOTEST] ... 12 | 13 | // at this point we have the remote-file and the local-file in the 14 | // command. d_firstword[1] contains the remote filename, 15 | // d_firstword[3] contains the rest 16 | 17 | string source = s_firstWord[1]; // get the (remote) source 18 | 19 | if (!source.length()) 20 | fmsg << "GET command requires source and destination" << noidl; 21 | 22 | s_firstWord.match(s_firstWord[3]); // strip off source 23 | string destination = s_firstWord[1]; // get the local dest. 24 | 25 | if (!destination.length()) 26 | fmsg << "GET " << source << 27 | " ': destination missing" << noidl; 28 | 29 | if (Stat(destination).isType(Stat::DIRECTORY)) // is the dest. a dir. ? 30 | destination += "/" + fileName(source); 31 | 32 | nextCommand(d_sshFork, // start the next command 33 | d_policyFile["DD"] + " if=" + source); 34 | 35 | read(d_sshFork, destination); // read its output, tests exit value 36 | } 37 | -------------------------------------------------------------------------------- /sourcetar: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PROJECT=stealth 3 | 4 | cd ~/git/${PROJECT}/src 5 | 6 | if [ -e /usr/share/common-licenses/GPL ] ; then 7 | cp /usr/share/common-licenses/GPL ${PROJECT}/LICENSE 8 | fi 9 | # load the version 10 | VERSION=`grep VERSION ${PROJECT}/VERSION | 11 | sed 's/#define[[:space:]]\+VERSION[[:space:]]\+"\(.*\)"/\1/'` 12 | 13 | DISTRIBUTION=${PROJECT}-${VERSION} # define the distribution's dir name 14 | 15 | tgz() 16 | { 17 | ln -s ${PROJECT} ${DISTRIBUTION} # distribution's dir name 18 | tar czvf $1 --exclude-from=excluded ${DISTRIBUTION}/* 19 | rm -f ${DISTRIBUTION} ${PROJECT}/LICENSE # rm the link/LICENSE file 20 | } 21 | 22 | case "$1" in 23 | (d) 24 | mkdir -p ../tarballs 25 | tgz ../tarballs/${PROJECT}_${VERSION}.orig.tar.gz 26 | ;; 27 | 28 | (l|o) 29 | tgz ${PROJECT}_${VERSION}.tar.gz 30 | 31 | if [ "$1" == "o" ] 32 | then 33 | scp ${PROJECT}_${VERSION}.tar.gz \ 34 | oosix:git/${PROJECT}/tarballs/${PROJECT}_${VERSION}.orig.tar.gz 35 | rm ${PROJECT}_${VERSION}.tar.gz 36 | fi 37 | ;; 38 | 39 | (*) 40 | echo " 41 | Provide arg: 42 | d (debian) to create a local .orig.tar.gz archive in 43 | ~/git/tarballs 44 | l (local) to create ${PROJECT}_${VERSION}.tar.gz in this directory 45 | o (oosix) same as 'l', but upload to oosix (IUO) 46 | " 47 | exit 1 48 | ;; 49 | 50 | esac 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /stealth/stealth/ipcinterface.cc: -------------------------------------------------------------------------------- 1 | #include "stealth.ih" 2 | 3 | // see also documentation/images/ipcinterface.jpg 4 | 5 | void Stealth::ipcInterface() 6 | try 7 | { 8 | string const &udsName = d_options.unixDomainSocket(); 9 | 10 | m2 << "Unix Domain Socket: " << udsName << endl; 11 | 12 | LocalServerSocket uds(udsName); 13 | 14 | uds.listen(); 15 | 16 | do 17 | { 18 | int socket = uds.accept(); // accept a request 19 | 20 | IFdStream in(socket); // stream to read the request from 21 | OFdStream out(socket); // stream to write answers to the 22 | // ipc-stealth process to. 23 | if (incomingRequest(in, out)) 24 | { 25 | d_ipc.wait(); // wait until an IPC command can be 26 | // accepted 27 | 28 | out << endl; // all commands succeed: empty return 29 | // texts indicates so. 30 | notifyTask(); 31 | } 32 | } 33 | while (not d_task.hasMode(TERMINATE)); 34 | } 35 | catch (exception const &exc) 36 | { 37 | ostringstream msg; 38 | msg << '\n' << exc.what() << "\n" 39 | " TERMINATING: exception in ipcInterface:\n"; 40 | 41 | imsg << msg.str() << endl; 42 | *d_report << msg.str() << endl; 43 | d_report->mail(); 44 | 45 | d_pending.setMode(TERMINATE); 46 | d_ipc.wait(); 47 | notifyTask(); 48 | } 49 | -------------------------------------------------------------------------------- /stealth/options/data.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | Options *Options::s_options = 0; 4 | 5 | char const Options::s_defaultSyslogIdent[] = "STEALTH"; 6 | Facility Options::s_defaultSyslogFacility = Facility::DAEMON; 7 | Priority Options::s_defaultSyslogPriority = Priority::NOTICE; 8 | 9 | LinearMap const Options::s_modeName = 10 | { 11 | {RELOAD, "reload"}, 12 | {RERUN, "rerun"}, 13 | {SUSPEND, "suspend"}, 14 | {RESUME, "resume"}, 15 | {TERMINATE, "terminate"} 16 | }; 17 | 18 | LinearMap const Options::s_syslogFacilities = 19 | { 20 | {"DAEMON", Facility::DAEMON}, 21 | {"LOCAL0", Facility::LOCAL0}, 22 | {"LOCAL1", Facility::LOCAL1}, 23 | {"LOCAL2", Facility::LOCAL2}, 24 | {"LOCAL3", Facility::LOCAL3}, 25 | {"LOCAL4", Facility::LOCAL4}, 26 | {"LOCAL5", Facility::LOCAL5}, 27 | {"LOCAL6", Facility::LOCAL6}, 28 | {"LOCAL7", Facility::LOCAL7}, 29 | {"USER", Facility::USER} 30 | }; 31 | 32 | LinearMap const Options::s_syslogPriorities = 33 | { 34 | {"EMERG", Priority::EMERG}, 35 | {"ALERT", Priority::ALERT}, 36 | {"CRIT", Priority::CRIT}, 37 | {"ERR", Priority::ERR}, 38 | {"WARNING", Priority::WARNING}, 39 | {"NOTICE", Priority::NOTICE}, 40 | {"INFO", Priority::INFO}, 41 | {"DEBUG", Priority::DEBUG} 42 | }; 43 | 44 | size_t Options::s_defaultVerbosity = 1; 45 | -------------------------------------------------------------------------------- /stealth/INSTALL.im: -------------------------------------------------------------------------------- 1 | // Specify the name of the project: 2 | #define PROJECT "stealth" 3 | 4 | // Compiler to use: 5 | #define CXX "g++" 6 | 7 | // The compiler options to use: 8 | #define CXXFLAGS "--std=c++17 -Wall -O2 -pthread -fdiagnostics-color=never" 9 | 10 | // Flags passed to the linker: 11 | #define LDFLAGS "-lpthread" 12 | 13 | #define CPOPTS 14 | 15 | 16 | // COMPONENTS TO INSTALL 17 | // ===================== 18 | 19 | // For an operational non-Debian installation, you probably must be 20 | // `root'. 21 | 22 | // If necessary, adapt DOC, HDR, LIB and MAN (below) to your situation. 23 | // The provided locations are used by Debian Linux. 24 | 25 | // With 'build install' you can dynamically specify a location to prepend 26 | // to the locations configured here, and select which components you want 27 | // to install 28 | 29 | // ONLY USE ABSOLUTE DIRECTORY NAMES: 30 | 31 | 32 | // the directory where the additional documentation is stored 33 | #define ADD "/usr/share/doc/"${PROJECT}"-doc" 34 | 35 | // the final program 36 | #define BINARY "/usr/bin/"${PROJECT} 37 | 38 | // the directory where the standard documentation is stored 39 | #define DOC "/usr/share/doc/"${PROJECT} 40 | 41 | // the directory whre the manual page is stored 42 | #define MAN "/usr/share/man/man1" 43 | 44 | // the directory whre the user guide is stored 45 | #define UGUIDE "/usr/share/doc/"${PROJECT}"-doc/manual" 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /stealth/documentation/manual/policy/defines.yo: -------------------------------------------------------------------------------- 1 | tt(DEFINE) directives can be used to define symbols for longer strings. 2 | A tt(DEFINE) directive is constructed as follows: 3 | verb( DEFINE name that what is defined by `name') 4 | Here, 5 | itemization( 6 | it() the tt(name) following tt(DEFINE) is the symbol that may be used in 7 | tt(USE) directives (see below) and tt(commands) (see below). 8 | it() tt(DEFINE) symbols can be used in other tt(DEFINE) symbols. However, 9 | it is the responsibility of the policy file's author to make sure that 10 | (indirect) circular definitions are avoided. E.g., after: 11 | verb( DEFINE A ${B} 12 | DEFINE B ${A} 13 | DEFINE C ${C} 14 | 15 | USE MAILARGS ${A} ${B} ${C}) 16 | tt(MAILARGS) will be expanded to 17 | verb( ${A} ${A} ${C}) 18 | it() The text following tt(DEFINE name) is then inserted literally into 19 | the tt(USE) directive or tt(command). 20 | 21 | Example: 22 | verb( DEFINE SSH /usr/bin/ssh frank@localhost -q 23 | DEFINE EXECSHA1 -xdev -perm /111 -type f -exec /usr/bin/sha1sum {} \;) 24 | The symbols defined by tt(DEFINE) directives may consist of letters, 25 | digits and the underscore characters (tt(_)). In the definition of the symbol 26 | any character can be used. However, initial and/or trailing blanks are removed 27 | from definitions. 28 | 29 | To insert a definition into a tt(USE) directive or tt(command) use the form 30 | verb( ${name}) 31 | E.g., tt(${EXECSHA1}). Concrete examples are provided below. 32 | ) 33 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/commands.yo: -------------------------------------------------------------------------------- 1 | The following commands are now defined: 2 | itemization( 3 | it() first, we copy the client's tt(sha1sum) program to the monitor. In 4 | practice, this should also include the shared object libraries that are used 5 | by tt(sha1sum), as they might have become corrupted as well; 6 | it() Once tt(sha1sum) is locally available its integrity is verified; 7 | it() Once the integrity of the client's tt(sha1sum) has been verified, it 8 | is used to verify the integrity of the client's tt(/usr/bin/find) program; 9 | it() Following this, all setuid and setgid root files are located and 10 | checked for integrity; 11 | it() Finally, the integrity of the client configuration files under 12 | tt(/etc) is verified; 13 | ) 14 | 15 | In this manual the bf(sha1sum)(1) program is frequently used when checking 16 | hash values. Stronger hash functions (like bf(sha256sum)(1)) might be 17 | preferred in practice. tt(sha256sum's) hash values are remarkably longer than 18 | tt(sha1sum's) hash values. When using these longer hash values in the manual 19 | it often clobbers the layout of examples. Therefore in this manual 20 | bf(sha1sum)(1) is continued to be used. 21 | 22 | Realize, however, that when updating existing policy files to use 23 | bf(sha256sum)(1) instead of bf(sha1sum)(1), that previously generated log 24 | files (that used bf(sha1sum)(1)) are incompatible with log files obtained when 25 | using bf(sha256sum)(1). In practice this means that new log files need to be 26 | generated, and any previously geneerated log files must be disregarded. 27 | 28 | -------------------------------------------------------------------------------- /stealth/policyfile/data.cc: -------------------------------------------------------------------------------- 1 | #include "policyfile.ih" 2 | 3 | char const PolicyFile::s_configFileBase[] = ".stealth"; // in $HOME 4 | 5 | pair const 6 | PolicyFile::s_defaultKeyword[] = 7 | { 8 | pair("BASE", "."), 9 | pair("DD", "/bin/dd"), 10 | pair("DIFF", "/usr/bin/diff"), 11 | pair("DIFFPREFIX", "2"), 12 | pair("EMAIL", "root"), 13 | pair("MAILER", "/usr/bin/mail"), 14 | pair("REPORT", "report"), 15 | pair("SH", "/bin/sh"), 16 | pair("MAILARGS", "-s \"STEALTH scan report\""), 17 | }; 18 | 19 | size_t PolicyFile::s_nDefaultKeywords = 20 | sizeof(s_defaultKeyword) / sizeof(pair); 21 | 22 | Pattern PolicyFile::s_firstWord("^\\s*([-_[:alnum:]]+)\\s+(.*)"); 23 | Pattern PolicyFile::s_comment("^\\s*[#]?"); 24 | Pattern PolicyFile::s_define("(\\$\\{([-_[:alnum:]]+)\\})"); 25 | // [0]: all text, 26 | // [1]: all ${NAME} text 27 | // [2]: NAME itself 28 | Pattern PolicyFile::s_log( 29 | "^\\s*" 30 | "(LOCAL\\s+)?" // 1 31 | "(NOTEST\\s+)?" // 2 32 | "CHECK\\s+(LOG\\s*=\\s*)?" // 3 33 | "(\\S+)"); // 4: name of the logfile 34 | 35 | -------------------------------------------------------------------------------- /stealth/util/realpath.cc: -------------------------------------------------------------------------------- 1 | #include "util.ih" 2 | 3 | string Util::realPath(string const &path) 4 | { 5 | String::Type type; 6 | vector component = String::split(&type, path, "/"); 7 | 8 | if (type != String::NORMAL) 9 | throw Exception() << "Filename `" << path << "': not supported"; 10 | 11 | component.resize( 12 | remove(component.begin(), component.end(), ".") 13 | - 14 | component.begin() 15 | ); 16 | 17 | while (true) 18 | { 19 | size_t from = find(component.begin(), component.end(), "..") 20 | - component.begin(); 21 | 22 | if (from == component.size()) // at the last entry: done 23 | break; 24 | 25 | size_t to = find_if(component.begin() + from + 1, component.end(), 26 | [&](string const &element) 27 | { 28 | return element != ".."; 29 | } 30 | ) - component.begin(); 31 | 32 | 33 | size_t count = to - from; // # ".." entries 34 | 35 | size_t firstErase = from >= count ? // first to erase 36 | from - count 37 | : 38 | 0; 39 | 40 | component.erase(component.begin() + firstErase, 41 | component.begin() + to); 42 | } 43 | 44 | string ret(1, '/'); 45 | 46 | for(auto &str: component) 47 | ret += str + '/'; 48 | 49 | ret.pop_back(); 50 | 51 | return ret; 52 | } 53 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/makepolicy.yo: -------------------------------------------------------------------------------- 1 | Here we assume that s() is run by em(root), and that root wants to 2 | store information about the host tt(client) under the subdirectory 3 | tt(/root/stealth/client). 4 | 5 | Furthermore, we assume that reports of s() integrity-scans should be sent to 6 | the user tt(admin@elsewhere), who is only interested in receiving a short 7 | summary of changes, as the full report can always be read at the monitor 8 | itself. To accomplish this a small support-script was developed, filtering the 9 | report generated by s() down to its essentials. 10 | 11 | As the tt(sha1sum) program on the client may be compromised, it is a good idea 12 | to start the integrity scan by transferring the client's tt(sha1sum) program 13 | to the monitor first, to verify the integrity of that program locally (i.e., 14 | at the monitor), before trusting it to compute sha1sums of the client's 15 | files. The same holds true for any libraries and support programs (like 16 | tt(find)) that are used intensively during integrity scans. 17 | 18 | Sha1sum checks should be performed on all setuid and setgid files on the 19 | tt(client), and in order to be able reach all files on tt(client), 20 | tt(root@monitor) is allowed to login to the tt(root@client) account using 21 | an tt(ssh) connection. 22 | 23 | Furthermore, sha1sum checks should be performed on all configuration files, 24 | living under tt(/etc) and on the file tt(/usr/bin/find) (which is used 25 | intensively when performing the integrity checks). 26 | 27 | Next, the construction of the required tt(policy) file, implementing the 28 | abovementioned requirements, is described in the following subsections. 29 | 30 | -------------------------------------------------------------------------------- /stealth/share/usr/bin/stealthcleanup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() 4 | { 5 | echo " 6 | Usage: $0 [-v] rc-file 7 | Where: 8 | -v: Show the actions that are performed 9 | rc-file: resource file defining: 10 | \`directories' - one or more directories containing status files 11 | \`gzdays' - number of days status files may exist before they 12 | are compressed 13 | \`rmdays' - number of days gzipped status files may exist 14 | before they are removed. 15 | " 16 | exit 1 17 | } 18 | 19 | 20 | error() 21 | { 22 | echo "$*" >&2 23 | exit 1 24 | } 25 | 26 | if [ "$1" == "-v" ] 27 | then 28 | verbose=1 29 | shift 1 30 | else 31 | verbose=0 32 | fi 33 | 34 | [ $# == 1 ] || usage 35 | 36 | # now source the configuration file 37 | . $1 38 | 39 | for x in $directories 40 | do 41 | cd $x || error "\`$x' must be a directory" 42 | if [ $verbose -eq 1 ] 43 | then 44 | echo " 45 | cd $x" 46 | fi 47 | 48 | if [ $verbose -eq 1 ] 49 | then 50 | echo \ 51 | /usr/bin/find ./ -mtime +$rmdays -type f -regex '.*[0-9]+-[0-9]+\.gz' \ 52 | -exec /bin/rm {} \; 53 | fi 54 | /usr/bin/find ./ -mtime +$rmdays -type f -regex '.*[0-9]+-[0-9]+\.gz' \ 55 | -exec /bin/rm {} \; 56 | 57 | if [ $verbose -eq 1 ] 58 | then 59 | echo \ 60 | /usr/bin/find ./ -mtime +$gzdays -type f -regex '.*[0-9]+-[0-9]+' \ 61 | -exec /bin/gzip {} \; 62 | fi 63 | /usr/bin/find ./ -mtime +$gzdays -type f -regex '.*[0-9]+-[0-9]+' \ 64 | -exec /bin/gzip {} \; 65 | done 66 | 67 | exit 0 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /stealth/integrityscanner/read.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // SEE ALSO THE MEMBER waitForSentinel() 4 | 5 | void IntegrityScanner::read(Process &src, string const &fname) 6 | { 7 | ofstream target(fname.c_str()); 8 | 9 | if (!target) 10 | fmsg << "can't write `" << fname << '\'' << noidl; 11 | 12 | char c; 13 | string partialSentinel; 14 | 15 | size_t length = 0; 16 | off_t size = 0; 17 | 18 | while (true) 19 | { 20 | if (not src.read(&c, 1)) // read char by char 21 | fmsg << "Incomplete read from `" << fname << "'" << noidl; 22 | 23 | checkSize(fname, ++size); // throws if not OK 24 | 25 | if (c == d_sentinel[length]) // got next sentinel char 26 | { 27 | length++; 28 | // matched the sentinel 29 | if (length == d_sentinel.length()) 30 | { 31 | m3 << "GOT Sentinel" << endl; 32 | 33 | string tail; // get the end-chars as well 34 | getline(src, tail); 35 | partialSentinel += tail; 36 | 37 | break; // so we're done. 38 | } 39 | partialSentinel += c; // append c to the partial Sentinel 40 | } 41 | else 42 | { 43 | if (length) 44 | { 45 | target.write(partialSentinel.c_str(), length); 46 | partialSentinel.erase(); 47 | length = 0; 48 | } 49 | target.write(&c, 1); 50 | } 51 | } 52 | testExitValue(src.str(), partialSentinel); 53 | } 54 | -------------------------------------------------------------------------------- /stealth/integrityscanner/integrityscanner1.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | /* 4 | Since the IntegrityScanner's destruction is also the termination of the 5 | program, no explicit destruction of the newly created objects is necessary. A 6 | pointer is used to prevent the construction of a constant object. As the 7 | constructor itself would create a constant object, the construction *new... 8 | is used. 9 | 10 | */ 11 | 12 | IntegrityScanner::IntegrityScanner(RunMode const &pending, Options &options, 13 | PolicyFile &policyFile, ostream &report) 14 | : 15 | d_options(options), 16 | d_pending(pending), 17 | d_policyFile(policyFile), 18 | d_report(report), 19 | d_firstWord("(\\S+)(\\s+(.*))?"), // firstword ([1]) and the 20 | // rest ([3]) of a text 21 | d_sshFork 22 | ( 23 | Process::CIN | Process::COUT | Process::IGNORE_CERR, 24 | d_policyFile["SSH"] 25 | ), // child: ignores stderr, reads 26 | d_shFork 27 | ( 28 | Process::CIN | Process::COUT | Process::IGNORE_CERR, 29 | d_policyFile["SH"] 30 | ), // from stdin/stdout 31 | // parent process communicates 32 | // via the Fork object's 33 | // stream interface. 34 | d_nScans(0), 35 | d_maxSize(d_options.maxDownloadSize()), 36 | 37 | d_diffPrefix(stoul(d_policyFile["DIFFPREFIX"])), 38 | d_pathOffset(numeric_limits::max()) 39 | { 40 | setSentinel(); 41 | loadSkipFiles(); 42 | } 43 | -------------------------------------------------------------------------------- /stealth/integrityscanner/put.cc: -------------------------------------------------------------------------------- 1 | #include "integrityscanner.ih" 2 | 3 | // Command forms: 4 | // PUT local-file remote-file 5 | // PUT NOTEST local-file remote-file 6 | 7 | void IntegrityScanner::put(string const &cmd) 8 | { 9 | removeFirstWord("PUT"); // strip off `PUT' 10 | 11 | d_testExitValue = !removeFirstWord("NOTEST"); // [NOTEST] ... 12 | 13 | // at this point we have the remote-file and the local-file in the 14 | // command. d_firstword[1] contains the remote filename, 15 | // d_firstword[3] contains the rest 16 | 17 | 18 | string source = s_firstWord[1]; // get the (remote) source 19 | if (!source.length()) 20 | fmsg << "PUT command requires source and destination" << noidl; 21 | 22 | s_firstWord.match(s_firstWord[3]); // strip off source 23 | 24 | string destination = s_firstWord[1]; // get the local dest. 25 | if (!destination.length()) 26 | fmsg << "At `PUT " << source << 27 | " ': destination missing" << 28 | noidl; 29 | 30 | if (Stat(destination).isType(Stat::DIRECTORY)) // is the dest. a dir. ? 31 | destination += "/" + fileName(source); // then append sourcename 32 | 33 | 34 | string command = putCommand(source, destination); 35 | 36 | d_sshFork << command << endl; // flush 37 | 38 | write(source); // write the file using dd 39 | 40 | d_sshFork << "/bin/echo \"" << d_sentinel << " $?\"" << endl; 41 | 42 | waitForSentinel(d_sshFork); 43 | } 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/cron.yo: -------------------------------------------------------------------------------- 1 | To automate s()'s integrity scans, a file 2 | tt(/etc/cron.d/stealth) could be created, containing a line like 3 | verb( 4 | 2,17,32,47 * * * * root test -x /usr/bin/stealth && \ 5 | /usr/bin/stealth /root/stealth/client.pol 6 | ) 7 | This starts s() 2 minutes after every hour. In this example the ssh-key 8 | must not require a passphrase, as bf(crontab)(1) cannot provide passphrases of 9 | ssh-keys. Ssh-keys requiring passphrases can, however, be used if repeated 10 | s() runs are controlled by a program like bf(ssh-cron)(1). 11 | 12 | In general, randomized events are harder to notice. For this s() offers 13 | the tt(--repeat) and tt(--random-interval) options. Both options expect an 14 | argument in seconds (or in minutes, if an tt(m) is appended to the 15 | specification). After each integrity scan the next integrity scan starts after 16 | the time interval specified by the tt(--repeat) option plus a random time 17 | value selected from the time interval specified by the tt(--random-interval) 18 | option. For example, the s() daemon started by the following command 19 | repeatedly performs integrity scans between two and five minutes after the 20 | last integrity scan completed: 21 | verb( 22 | stealth --daemon /root/stealth/client.uds \ 23 | --repeat 2m --random-interval 3m /root/stealth/client.pol) 24 | Once this program has started its bf(ssh)(1) connection to the client host 25 | persists, and a possibly required ssh-passphrase is no longer 26 | required. Additional (intermediate) integrity scans can always be requested 27 | (also without requiring ssh-passphrase specifications) using the command 28 | verb( 29 | stealth --rerun /root/stealth/client.uds) 30 | 31 | -------------------------------------------------------------------------------- /stealth/options/options1.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | // No log-files are available yet. But since Options is constructed while 4 | // stealth runs in the foreground, error messages can be sent to cerr. 5 | 6 | Options::Options() 7 | : 8 | d_arg(ArgConfig::instance()), 9 | d_base(getCwd()), 10 | d_maxSizeStr("10M"), 11 | d_repeatInterval(numeric_limits::max()) 12 | { 13 | 14 | requireSomeArgument(); // no args/options, then usage and ends. 15 | 16 | oldOptions(); // ends if --keep-alive or --suppress was 17 | // specified 18 | 19 | setMode(); // sets d_mode and all bool mode indicators 20 | checkMode(); // ends if multiple/incompatible modes were 21 | // set 22 | 23 | d_dryrun = d_arg.option(0, "dry-run"); 24 | 25 | // preset file name options when defined as 26 | // command-line options, using base = cwd 27 | d_cmdLineOption = setLog() | setSkipFile(); 28 | 29 | setCommandNr(); // sets run-command, (requires foreground). 30 | setParsePolicy(); // sets the policy file (requires foreground) 31 | 32 | setPolicyPath(); 33 | 34 | if (d_daemon) 35 | { 36 | Util::absPath(d_base, d_unixDomainSocket); 37 | 38 | if (access(d_unixDomainSocket.c_str(), F_OK) == 0) 39 | fmsg << "Unix Domain Socket `" << d_unixDomainSocket << 40 | "': already in use, remove it first" << noidl; 41 | } 42 | 43 | setConfigOptions(); 44 | 45 | if 46 | ( 47 | not d_skipFile.empty() 48 | and 49 | access(d_skipFile.c_str(), R_OK) != 0 50 | ) 51 | fmsg << "Can't read skip-file `" << d_skipFile << '\'' << noidl; 52 | 53 | 54 | } 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/skipping.yo: -------------------------------------------------------------------------------- 1 | Some files or directories may not require integrity checks. Automated 2 | processes may modify files which are not threatening the proper functioning of 3 | running programs or processes. In those cases a file can be prepared holding 4 | the absolute paths of entries to be skipped. Each entry should appear on a 5 | line of its own without any additional information. 6 | 7 | S() can be informed about this file using the tt(--skip-files ) 8 | option. When a relative file specification is used with tt(--skip-files) it is 9 | interpreted a location relative to the current working directory. The 10 | skip-files file itself must contain the paths of the entries to be skipped 11 | during file integrity scans. If an entry is already present in a log file then 12 | s() once generates an tt(IGNORING) message in the mail sent to the address 13 | specified at tt(EMAIL) in the policy file. Each entry in a skip-file must be 14 | on a line of its own and must be specified using absolute file paths. Entries 15 | ending in a slash are assumed to be directories whose full contents must be 16 | skipped. Other entries are interpreted as the names of files to skip. Initial 17 | and trailing blanks, empty lines and lines having a tt(#) as their 1st non 18 | blank character are ignored. 19 | 20 | Here is an example: 21 | verb( 22 | stealth -e --skip-files /root/stealth/remote/skipping remote.pol) 23 | 24 | If an entry tt(/etc/skipme) appears in the current logs which is thereafter 25 | added to the tt(skippath) file then the mail generated by s() 26 | once contains a line like the following: 27 | verb( SKIPPING: /etc/skipme 28 | > a7695bb2d019e60988e757a4b692acfe /etc/skipme 29 | ) 30 | The reported hash-value is the hash-value at the time of the stealth-run 31 | reporting the tt(SKIPPING) message. 32 | 33 | Entries ending in a slash are assumed to be directories whose contents must 34 | (recursively) be skipped. 35 | -------------------------------------------------------------------------------- /stealth/README.messages: -------------------------------------------------------------------------------- 1 | Messages sent to m1, m2, and m3 (see ../msg) are sent to imsg. 2 | 3 | LogUnit::setupLogs() creates an FBB::Log and FBB::SyslogSteam if requested so 4 | by options. 5 | 6 | It adds these files to an FBB::MultiStreambuf, and (if requested by --stdout) 7 | also adds cout. 8 | 9 | If any streams are stored, the MultiStreambuf is installed in imsg. Following 10 | this, all messages inserted into imsg are sent to the requested log streams. 11 | 12 | Fatal messages, sent to fmsg, are handled similarly: 13 | 14 | A MultiStreambuf receives imsg, and optionally (when calling setupLogs(ostream 15 | &report)) into the ostream which inserts messages into the Report object. 16 | 17 | The stream received by setupLogs is itself a wrapper around the actual Report 18 | object, and its streambuf is defined in stealth/stealth.ih: all text inserted 19 | into fmsg is also sent to this wrapper ostream, which forwards its characters 20 | to its streambuffer's overflow member. This member sends all its characters to 21 | Stealth's d_report object. When the wrapper stream is flushed, it calls 22 | d_report.mail(), to process d_report's info by mail. 23 | 24 | LogUnit: 25 | ======== 26 | 27 | SyslogStream --+ 28 | | 29 | Log --+--> MultiStreambuf 30 | | | 31 | cout (with --stdout) --+ | 32 | | 33 | | 34 | v 35 | imsg.reset(...) 36 | | 37 | +----------+----------+ 38 | m1 m2 m3 39 | 40 | 41 | imsg ----+ 42 | | 43 | +--> MultiStreambuf 44 | | | 45 | report ----+ | 46 | | 47 | v 48 | fmsg.reset(...) 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /stealth/options/oldoptions.cc: -------------------------------------------------------------------------------- 1 | #include "options.ih" 2 | 3 | void Options::oldOptions() const 4 | { 5 | ostringstream msg; 6 | 7 | int nOld = 0; 8 | 9 | if (d_arg.option('e')) 10 | { 11 | ++nOld; 12 | msg << " `--echo-commands' was discontinued. " 13 | "Use --verbosity 2.\n"; 14 | } 15 | 16 | bool usedKeepAlive = d_arg.option(0, "keep-alive"); 17 | if (usedKeepAlive) 18 | { 19 | ++nOld; 20 | msg << " `--keep-alive' was discontinued. Use --daemon.\n"; 21 | } 22 | 23 | if (d_arg.option('n')) 24 | { 25 | ++nOld; 26 | msg << " `--no-child-process' was discontinued.\n"; 27 | } 28 | 29 | if (d_arg.option(0, "only-stdout")) 30 | { 31 | ++nOld; 32 | msg << " `--only-stdout' was discontinued. " 33 | "Consider using --stdout.\n"; 34 | } 35 | 36 | if (d_arg.option('c')) 37 | { 38 | ++nOld; 39 | msg << " `--parse-config-file' was discontinued. " 40 | "Use --parse-policy-file.\n"; 41 | } 42 | 43 | if (d_arg.option('q')) 44 | { 45 | ++nOld; 46 | msg << " `--quiet' was discontinued. Use --verbosity 0.\n"; 47 | } 48 | 49 | bool usedSuppress = d_arg.option(0, "suppress"); 50 | if (usedSuppress) 51 | { 52 | ++nOld; 53 | msg << " `--suppress' was discontinued. Use --suspend.\n"; 54 | } 55 | 56 | if (nOld != 0) 57 | { 58 | wmsg << "\n" << 59 | basename() << " V" << Icmbuild::version << "\n" 60 | "Obsoleted option(s):\n" << 61 | msg.str(); 62 | 63 | if (usedKeepAlive or usedSuppress) 64 | fmsg << basename() << " V. " << Icmbuild::version << 65 | " terminated" << noidl; 66 | else 67 | wmsg << flush; 68 | } 69 | } 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /stealth/documentation/manual/policy/intro.yo: -------------------------------------------------------------------------------- 1 | S() uses a policy file consisting of two sections, the second 2 | section is optional, and starts at a line merely containing tt(%%). 3 | 4 | Each policy file is uniquely associated with a host to be tested. Each host 5 | may have multiple policy files, though. In that case, each policy file defines 6 | its own set of checks to be performed. 7 | 8 | itemization( 9 | it() The policy file's first section consists of two sets of data: em(use 10 | directives) (starting with the keyword bf(USE)) and em(commands). 11 | 12 | it() The (optional) second section starts at a line merely containing 13 | tt(%%). Following this separating line several long option specifications can 14 | be entered (cf. section ref(OPTIONS)). Options 15 | specified on the command-line take priority over options specified 16 | in the policy file. Although the tt(--reload) option reloads the policy file, 17 | it will not change option values originally specified as command-line options. 18 | 19 | This section may contain specifications of the tt(skip-files) and tt(log) 20 | options. Relative file locations specified for these options are interpreted 21 | relative to the location of the policy file. E.g., if the policy file argument 22 | is specified as tt(/root/client/policy) then the specification tt(log: 23 | client.log) results in s() writing its logs into the file 24 | tt(/root/client/client.log). 25 | ) 26 | 27 | 28 | The policy file's first section consists of three sets of data: em(define 29 | directives) (starting with the keyword bf(DEFINE)), em(use directives) 30 | (starting with the keyword bf(USE)) and em(commands). 31 | 32 | Directives are written in capitals, and should appear exactly as written 33 | below. 34 | 35 | Blank lines and information beyond hash-marks (#) are ignored, while lines 36 | following lines terminating in backslashes (\ ) will be concatenated (em(en 37 | passant) removing these backslashes). Leading white space on lines of the 38 | policy file is ignored. 39 | 40 | 41 | -------------------------------------------------------------------------------- /stealth/documentation/manual/running/status.yo: -------------------------------------------------------------------------------- 1 | Whenever s() is run and it encounters a modified situation the already 2 | existing status file summarizing that particular situation is saved and a new 3 | status file is created. Eventually, this will result in many status 4 | files. While report files can be rotated, it is pointless to rotate old status 5 | files, since they are never modified. Instead, status files exceeding a 6 | certain age could be removed and more recent files might be zipped to conserve 7 | space. In s()'s binary distribution the file 8 | tt(/usr/share/doc/stealth/usr/bin/stealthcleanup) is provided which can be 9 | used to perform such a cleanup. The script expects one argument: a resource 10 | file defining the following shell variables: 11 | itemization( 12 | it() tt(directories): the directories below which the status files are 13 | found; 14 | it() tt(gzdays): the number of days a status file must exist before it is 15 | compressed using bf(gzip)(1); 16 | it() tt(rmdays): the maximum age (in days) of compressed status 17 | files. Files exceeding this age are removed using bf(rm)(1). 18 | ) 19 | Here is the tt(stealthcleanup) script as contained in the binary 20 | distribution's tt(/usr/share/doc/stealth/usr/bin) directory: 21 | verbinclude(../../../share/usr/bin/stealthcleanup) 22 | Assuming that the status files are written in 23 | tt(/var/stealth/target/local) and tt(/var/stealth/target/remote); that status 24 | file should be compressed when older than 2 days and removed after 30 days, 25 | the resource file is: 26 | verbinclude(../../../share/etc/stealth/cleanup.rc) 27 | Furthermore assuming that the resourcefile is installed in 28 | tt(/etc/stealth/cleanup.rc) and the tt(stealthcleanup) script itself in 29 | tt(/usr/bin/stealthcleanup), the tt(stealthcleanup) script could be called 30 | as follows: 31 | verb( 32 | /usr/bin/stealthcleanup /etc/stealth/cleanup.rc) 33 | Note that tt(stealthcleanup) may be called whether or not there are active 34 | s() processes. 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /stealth/README.3.00.00: -------------------------------------------------------------------------------- 1 | This file summarizes the changes from stealth 2.12.00 to stealth.3.00.00 2 | Consult the man-page and manual for more extensive information. 3 | 4 | Affected options: 5 | 6 | --echo-commands: replaced by --log 7 | --keep-alive: replaced by --daemon 8 | --only-stdout: replaced by --stdout 9 | --parse-config-file: replaced by --parse-policy-file 10 | --quiet: replaced by --verbosity 11 | --suppress: replaced by --suspend 12 | 13 | --debug: discontinued. Use --verbosity and/or --dry-run 14 | instead. 15 | --no-child-processes: discontinued. 16 | 17 | New options: 18 | 19 | --daemon: run as background (daemon) process; 20 | --dry-run: no integrity scans or reloads are performed; 21 | --log: log messages are written to a file; 22 | --logmail: mail sent by s() is also logged; 23 | --no-mail: mail is not sent; 24 | --parse-policy-file: parse the policy file; 25 | --stdout: messages are (also) written to the std. output 26 | stream; 27 | --suspend: suspends a currently active s() process; 28 | --syslog: write syslog messages; 29 | --syslog-facility: sets the syslog facility to use; 30 | --syslog-priority: sets the syslog priority to use; 31 | --syslog-tag: specifies an identifier that is prefixed to 32 | syslog messages; 33 | --verbosity : determines the amount of logged information. 34 | 35 | 36 | The policy file now contains two sections. 37 | 38 | The first section is identical to the 2.12.00 configuration file. 39 | The second section starts at a line merely containing tt(%%), is optional, 40 | and may contain (some) long option specifications. See the manual/man-page 41 | OPTIONS section for details. 42 | -------------------------------------------------------------------------------- /stealth/CHANGELOG: -------------------------------------------------------------------------------- 1 | 1.31 2 | 3 | Added options --suppress and --resume to allow logfile rotations 4 | --resume implies a --rerun 5 | --terminate can be used following --suppress 6 | 7 | Removed ::exit() and atexit() calls, using exceptions instead. 8 | 9 | Added `Monitor', containing all process-control functions previously 10 | provided by Scanner itself. Scanner now only performs the scanning 11 | functions. 12 | 13 | 1.20.2 (Debian) and beyond: 14 | =========================== 15 | 16 | See the debian changelog file for all changes as of version 1.20.2 17 | 18 | 1.20 19 | ==== 20 | 21 | Long options added (1.11), `LOG =' may be specified with CHECK commands. 22 | 23 | Starting version 1.20, a Debian package is provided in parallel to the source 24 | package. The Debian package contains the full documentation, as well as the 25 | binary version of the stealth program. 26 | 27 | 1.10 28 | ==== 29 | 30 | -i