| [1] | 1 | <html>
 | 
|---|
 | 2 | <head>
 | 
|---|
 | 3 | <title>HOWTO Write Samhain Modules</title>
 | 
|---|
 | 4 | <style type="text/css">
 | 
|---|
 | 5 | <!--
 | 
|---|
 | 6 | 
 | 
|---|
 | 7 | html { background: #eee; color: #000; }
 | 
|---|
 | 8 | 
 | 
|---|
 | 9 | body { background: #eee; color: #000; margin: 0; padding: 0;}
 | 
|---|
 | 10 | 
 | 
|---|
 | 11 | div.body {
 | 
|---|
 | 12 |         background: #fff; color: #000;
 | 
|---|
 | 13 |         margin: 0 1em 0 1em; padding: 1em;
 | 
|---|
 | 14 |         font-family: serif;
 | 
|---|
 | 15 |         font-size: 1em; line-height: 1.2em;
 | 
|---|
 | 16 |         border-width: 0 1px 0 1px;
 | 
|---|
 | 17 |         border-style: solid;
 | 
|---|
 | 18 |         border-color: #aaa;
 | 
|---|
 | 19 | }
 | 
|---|
 | 20 | 
 | 
|---|
 | 21 | div.block {
 | 
|---|
 | 22 |         background: #b6c5f2; color: #000;
 | 
|---|
 | 23 |         margin: 1em; padding: 0 1em 0 1em;
 | 
|---|
 | 24 |         border-width: 1px;
 | 
|---|
 | 25 |         border-style: solid;
 | 
|---|
 | 26 |         border-color: #2d4488;
 | 
|---|
 | 27 | }
 | 
|---|
 | 28 | 
 | 
|---|
 | 29 | div.warnblock {
 | 
|---|
 | 30 |         background: #b6c5f2; color: #000;
 | 
|---|
 | 31 |         margin: 1em; padding: 0 1em 0 1em;
 | 
|---|
 | 32 |         border-width: 1px;
 | 
|---|
 | 33 |         border-style: solid;
 | 
|---|
 | 34 |         border-color: #FF9900;
 | 
|---|
 | 35 | }
 | 
|---|
 | 36 | 
 | 
|---|
 | 37 | table {
 | 
|---|
 | 38 |         background: #F8F8F8; color: #000;
 | 
|---|
 | 39 |         margin: 1em;
 | 
|---|
 | 40 |         border-width: 0 0 0 1px;
 | 
|---|
 | 41 |         border-style: solid;
 | 
|---|
 | 42 |         border-color: #C0C0C0;
 | 
|---|
 | 43 | }
 | 
|---|
 | 44 | 
 | 
|---|
 | 45 | td {
 | 
|---|
 | 46 |         border-width: 0 1px 1px 0;
 | 
|---|
 | 47 |         border-style: solid;
 | 
|---|
 | 48 |         border-color: #C0C0C0;
 | 
|---|
 | 49 | }
 | 
|---|
 | 50 | 
 | 
|---|
 | 51 | th {
 | 
|---|
 | 52 |         background: #F8F8FF;
 | 
|---|
 | 53 |         border-width: 1px 1px 2px 0;
 | 
|---|
 | 54 |         border-style: solid;
 | 
|---|
 | 55 |         border-color: #C0C0C0;
 | 
|---|
 | 56 | }
 | 
|---|
 | 57 | 
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 | /* body text, headings, and rules */
 | 
|---|
 | 60 | 
 | 
|---|
 | 61 | p { margin: 0; text-indent: 0em; margin: 0 0 0.5em 0 }
 | 
|---|
 | 62 | 
 | 
|---|
 | 63 | h1, h2, h3, h4, h5, h6 {
 | 
|---|
 | 64 |         color: #206020; background: transparent;
 | 
|---|
 | 65 |         font-family: Optima, Arial, Helvetica, sans-serif;
 | 
|---|
 | 66 |         font-weight: normal;
 | 
|---|
 | 67 | }
 | 
|---|
 | 68 | 
 | 
|---|
 | 69 | h1 { font-size: 1.69em; margin: 1.4em 0 0.4em 0; }
 | 
|---|
 | 70 | h2 { font-size: 1.44em; margin: 1.4em 0 0.4em 0; }
 | 
|---|
 | 71 | h3 { font-size: 1.21em; margin: 1.4em 0 0.4em 0; }
 | 
|---|
 | 72 | h4 { font-size: 1.00em; margin: 1.4em 0 0.4em 0; }
 | 
|---|
 | 73 | h5 { font-size: 0.81em; margin: 1.4em 0 0.4em 0; }
 | 
|---|
 | 74 | h6 { font-size: 0.64em; margin: 1.4em 0 0.4em 0; }
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 | hr {
 | 
|---|
 | 77 |         color: transparent; background: transparent;
 | 
|---|
 | 78 |         height: 0px; margin: 0.6em 0;
 | 
|---|
 | 79 |         border-width: 1px ;
 | 
|---|
 | 80 |         border-style: solid;
 | 
|---|
 | 81 |         border-color: #999;
 | 
|---|
 | 82 | }
 | 
|---|
 | 83 | 
 | 
|---|
 | 84 | /* bulleted lists and definition lists */
 | 
|---|
 | 85 | 
 | 
|---|
 | 86 | ul { margin: 0 1em 0.6em 2em; padding: 0; }
 | 
|---|
 | 87 | li { margin: 0.4em 0 0 0; }
 | 
|---|
 | 88 | 
 | 
|---|
 | 89 | dl { margin: 0.6em 1em 0.6em 2em; }
 | 
|---|
 | 90 | dt { color: #285577; }
 | 
|---|
 | 91 | 
 | 
|---|
 | 92 | tt { color: #602020; }
 | 
|---|
 | 93 | 
 | 
|---|
 | 94 | /* links */
 | 
|---|
 | 95 | 
 | 
|---|
 | 96 | a.link {
 | 
|---|
 | 97 |         color: #33c; background: transparent;
 | 
|---|
 | 98 |         text-decoration: none;
 | 
|---|
 | 99 | }
 | 
|---|
 | 100 | 
 | 
|---|
 | 101 | a:hover {
 | 
|---|
 | 102 |         color: #000; background: transparent;
 | 
|---|
 | 103 | }
 | 
|---|
 | 104 | 
 | 
|---|
 | 105 | body > a {
 | 
|---|
 | 106 |         font-family: Optima, Arial, Helvetica, sans-serif;
 | 
|---|
 | 107 |         font-size: 0.81em;
 | 
|---|
 | 108 | }
 | 
|---|
 | 109 | 
 | 
|---|
 | 110 | h1, h2, h3, h4, h5, h6 {
 | 
|---|
 | 111 |         color: #2d5588; background: transparent;
 | 
|---|
 | 112 |         font-family: Optima, Arial, Helvetica, sans-serif;
 | 
|---|
 | 113 |         font-weight: normal;
 | 
|---|
 | 114 | }
 | 
|---|
 | 115 | 
 | 
|---|
 | 116 |   -->
 | 
|---|
 | 117 | </style></head>
 | 
|---|
 | 118 | 
 | 
|---|
 | 119 | <body>
 | 
|---|
 | 120 | <div class="body">
 | 
|---|
 | 121 | <p style="text-align: center; background: #ccc; border: 1px solid #2d5588;"><a 
 | 
|---|
 | 122 |    style="text-decoration: none;" 
 | 
|---|
 | 123 |    href="http://www.la-samhna.de/samhain/">samhain file integrity 
 | 
|---|
 | 124 |    scanner</a> | <a style="text-decoration: none;" 
 | 
|---|
 | 125 |    href="http://www.la-samhna.de/samhain/s_documentation.html">online 
 | 
|---|
 | 126 |    documentation</a></p>
 | 
|---|
 | 127 | <br><center>
 | 
|---|
 | 128 | <h1>Writing modules for samhain</h1>
 | 
|---|
 | 129 | </center>
 | 
|---|
 | 130 | <br>
 | 
|---|
 | 131 | <hr>
 | 
|---|
 | 132 | <p>
 | 
|---|
 | 133 | This document should help anyone who is sitting down to write a module
 | 
|---|
 | 134 | for the samhain host intrusion detection system. We give an overview
 | 
|---|
 | 135 | of samhain's structure from the point of view of the module author,
 | 
|---|
 | 136 | and describe some of the samhain utility and interface functions
 | 
|---|
 | 137 | available. Lastly, we explain how to integrate your module into the
 | 
|---|
 | 138 | samhain autoconf build tools.
 | 
|---|
 | 139 | </p>
 | 
|---|
 | 140 | <h2>Introduction</h2>
 | 
|---|
 | 141 | <p>
 | 
|---|
 | 142 | Samhain is a rather useful file integrity and host intrusion detection
 | 
|---|
 | 143 | system.  It is written entirely in C, and much care has been given to
 | 
|---|
 | 144 | making it robust and secure. Additionally, it has been written with
 | 
|---|
 | 145 | extensibility in mind, and so interfaces for adding user-contributed
 | 
|---|
 | 146 | modules have been provided. A module author can easily extend the
 | 
|---|
 | 147 | configuration file syntax and have his checking code run on a regular
 | 
|---|
 | 148 | basis as one of samhain's internal checks.
 | 
|---|
 | 149 | </p>
 | 
|---|
 | 150 | 
 | 
|---|
 | 151 | <h2>Prerequisites</h2>
 | 
|---|
 | 152 | <p>
 | 
|---|
 | 153 | You'll need to know how to read and write C. You'll need the latest
 | 
|---|
 | 154 | source for samhain.  You'll need to have read all of samhain's other
 | 
|---|
 | 155 | documentation. Finally, if you want to make your module build as part
 | 
|---|
 | 156 | of the samhain tree (you do), you'll need GNU's autoconf package.
 | 
|---|
 | 157 | </p>
 | 
|---|
 | 158 | <h2>An overview of samhain's execution</h2>
 | 
|---|
 | 159 | <p>
 | 
|---|
 | 160 | Here's what happens when samhain starts:
 | 
|---|
 | 161 | <ul>
 | 
|---|
 | 162 |         <li>
 | 
|---|
 | 163 |         Check if samhain has been called with one of the "init.d" type 
 | 
|---|
 | 164 |         commands - start, stop, reload, status. If so, these are handled 
 | 
|---|
 | 165 |         as you might expect. Nice feature.
 | 
|---|
 | 166 |         </li>
 | 
|---|
 | 167 |         <li>
 | 
|---|
 | 168 |         Initialise all global structures and parse command-line options.
 | 
|---|
 | 169 |         </li>
 | 
|---|
 | 170 |         <li>
 | 
|---|
 | 171 |         Read the configuration file. This is handled in sh_readconf_read(). 
 | 
|---|
 | 172 |         This includes attempting to download the file if samhain has been 
 | 
|---|
 | 173 |         compiled to do so. 
 | 
|---|
 | 174 |         </li>
 | 
|---|
 | 175 |         <li>
 | 
|---|
 | 176 |         Drop privileges if server.
 | 
|---|
 | 177 |         </li>
 | 
|---|
 | 178 |         <li>
 | 
|---|
 | 179 |         Test the checksum on the database if client or standalone.
 | 
|---|
 | 180 |         </li>
 | 
|---|
 | 181 |         <li>
 | 
|---|
 | 182 |         Now test if samhain has been compiled as a client or a server.
 | 
|---|
 | 183 |         <ul>
 | 
|---|
 | 184 |                 <li>
 | 
|---|
 | 185 |                 If server, enter server main loop sh_receive() in 
 | 
|---|
 | 186 |                 sh_forward.c. This is simple enough; apart from checks for 
 | 
|---|
 | 187 |                 signals received, the server just accepts incoming 
 | 
|---|
 | 188 |                 connections, verifies that they are from an authorised 
 | 
|---|
 | 189 |                 client, and logs the message received.
 | 
|---|
 | 190 |                 </li>
 | 
|---|
 | 191 |                 <li>
 | 
|---|
 | 192 |                 If client or standalone, we run the rest of main() in 
 | 
|---|
 | 193 |                 samhain.c, which follows:
 | 
|---|
 | 194 |                 </li>
 | 
|---|
 | 195 |         </ul>
 | 
|---|
 | 196 |         </li>
 | 
|---|
 | 197 |         <li>
 | 
|---|
 | 198 |         Initialise modules - that is, call the mod_init() function on each 
 | 
|---|
 | 199 |         module. Note that if the module intialisation routine returns a 
 | 
|---|
 | 200 |         nonzero value, you should also have it free anything that's been 
 | 
|---|
 | 201 |         allocated by the configuration file reading functions, since this 
 | 
|---|
 | 202 |         method is always called after an sh_readconf_read(), i.e. when the
 | 
|---|
 | 203 |         configuration file is re-read after a SIGHUP.
 | 
|---|
 | 204 |         </li>
 | 
|---|
 | 205 |         <li>
 | 
|---|
 | 206 |         Test the setup that's been read from the configuration - for example, 
 | 
|---|
 | 207 |         check if any files or directories have been defined twice.
 | 
|---|
 | 208 |         </li>
 | 
|---|
 | 209 |         <li>
 | 
|---|
 | 210 |         Enter the main loop (which runs just once if samhain is not 
 | 
|---|
 | 211 |         configured as a daemon). Test if any signals have been received, 
 | 
|---|
 | 212 |         and handle them appropriately:
 | 
|---|
 | 213 |         <ul>
 | 
|---|
 | 214 |                 <li>
 | 
|---|
 | 215 |                 On reconfiguration (SIGHUP), clear internal file lists etc. 
 | 
|---|
 | 216 |                 and call the mod_reconf() function on each module. This should
 | 
|---|
 | 217 |                 clean up anything internal to the module before the 
 | 
|---|
 | 218 |                 configuration file is re-read. Then read the configuration 
 | 
|---|
 | 219 |                 file again and set things up as before, including a new call 
 | 
|---|
 | 220 |                 to mod_init().
 | 
|---|
 | 221 |                 </li>
 | 
|---|
 | 222 |                 <li>
 | 
|---|
 | 223 |                 On SIGIOT (SIGABRT), shut down the log-file for a moment 
 | 
|---|
 | 224 |                 to allow for rotation.
 | 
|---|
 | 225 |                 </li>
 | 
|---|
 | 226 |                 <li>
 | 
|---|
 | 227 |                 On SIGQUIT, terminate. Note that any call to exit() will 
 | 
|---|
 | 228 |                 invoke the exit_handler() defined in samhain.c; the first 
 | 
|---|
 | 229 |                 thing this does is to call mod_cleanup() on all modules. 
 | 
|---|
 | 230 |                 Then it cleans up everything else in samhain and exits.
 | 
|---|
 | 231 |                 </li>
 | 
|---|
 | 232 |                 <li>
 | 
|---|
 | 233 |                 On SIGUSR1 turn toggle debugging on/off.
 | 
|---|
 | 234 |                 </li>
 | 
|---|
 | 235 |                 <li>
 | 
|---|
 | 236 |                 On SIGUSR2 suspend the daemon an notify the server to
 | 
|---|
 | 237 |                 allow a second instance of samhain downloading its
 | 
|---|
 | 238 |                 configuration file without triggering an alert (restart
 | 
|---|
 | 239 |                 without exit) on the server.
 | 
|---|
 | 240 |                 </li>
 | 
|---|
 | 241 |         </ul>
 | 
|---|
 | 242 |         </li>
 | 
|---|
 | 243 |         <li>
 | 
|---|
 | 244 |         If it's time to check files, check directories and then files, and 
 | 
|---|
 | 245 |         then flush the mail queue.
 | 
|---|
 | 246 |         </li>
 | 
|---|
 | 247 |         <li>
 | 
|---|
 | 248 |         Execute modules. For each module, if mod_timer(tcurrent) returns a 
 | 
|---|
 | 249 |         nonzero value, then execute mod_check().
 | 
|---|
 | 250 |         </li>
 | 
|---|
 | 251 |         <li>
 | 
|---|
 | 252 |         Do various maintenance operations such as logging a timestamp/sending 
 | 
|---|
 | 253 |         some mail if it's time, seeding/re-seeding the PRNG, etc.
 | 
|---|
 | 254 |         </li>
 | 
|---|
 | 255 | </ul>
 | 
|---|
 | 256 | You'll note that in the text above I refer to a couple of module
 | 
|---|
 | 257 | functions - mod_init(), mod_check(), etc. These are function pointers
 | 
|---|
 | 258 | that act as hooks for attaching modules to samhain. Next we'll
 | 
|---|
 | 259 | describe how they are used.
 | 
|---|
 | 260 | </p>
 | 
|---|
 | 261 | 
 | 
|---|
 | 262 | <h2>Samhain's module interface</h2>
 | 
|---|
 | 263 | <p>
 | 
|---|
 | 264 | Here we'll describe the interface samhain provides to module authors.
 | 
|---|
 | 265 | </p>
 | 
|---|
 | 266 | 
 | 
|---|
 | 267 | <h3>The module list</h3>
 | 
|---|
 | 268 | <p>
 | 
|---|
 | 269 | In sh_modules.h, the following structure is defined:
 | 
|---|
 | 270 | </p>
 | 
|---|
 | 271 | <pre>
 | 
|---|
 | 272 | 
 | 
|---|
 | 273 | typedef struct mod_type
 | 
|---|
 | 274 | {
 | 
|---|
 | 275 |   /* The name of the module                                    */
 | 
|---|
 | 276 |   char * name;      
 | 
|---|
 | 277 | 
 | 
|---|
 | 278 |   /* Set by samhain to 1 on successful initialization, else 0  */
 | 
|---|
 | 279 |   int    initval; 
 | 
|---|
 | 280 | 
 | 
|---|
 | 281 |   /* The initialization function. Return 0 on success.         */
 | 
|---|
 | 282 |   int (* mod_init)    (void);  
 | 
|---|
 | 283 |                              
 | 
|---|
 | 284 |   /* The timer function. Return 0 if NOT time to check.        */
 | 
|---|
 | 285 |   int (* mod_timer)   (unsigned long tcurrent); 
 | 
|---|
 | 286 | 
 | 
|---|
 | 287 |   /* The check function. Return 0 on success.                  */
 | 
|---|
 | 288 |   int (* mod_check)   (void); 
 | 
|---|
 | 289 | 
 | 
|---|
 | 290 |   /* The cleanup function. Return 0 on success.                */
 | 
|---|
 | 291 |   int (* mod_cleanup) (void);
 | 
|---|
 | 292 | 
 | 
|---|
 | 293 |   /* The preparation for reconfiguration. Return 0 on success. */
 | 
|---|
 | 294 |   int (* mod_reconf) (void);
 | 
|---|
 | 295 | 
 | 
|---|
 | 296 |   /* Section header in config file                             */
 | 
|---|
 | 297 |   char * conf_section; 
 | 
|---|
 | 298 | 
 | 
|---|
 | 299 |   /* A table of key/handler_function for config file entries   */
 | 
|---|
 | 300 |   sh_rconf * conf_table; 
 | 
|---|
 | 301 | 
 | 
|---|
 | 302 | } sh_mtype;
 | 
|---|
 | 303 | </pre>
 | 
|---|
 | 304 | 
 | 
|---|
 | 305 | <p>
 | 
|---|
 | 306 | This is the structure used to hook modules into samhain. There is a
 | 
|---|
 | 307 | list of these structures (modList), defined in sh_modules.c,
 | 
|---|
 | 308 | containing pointers to the functions to be used for each module
 | 
|---|
 | 309 | compiled into samhain. For example,
 | 
|---|
 | 310 | </p>
 | 
|---|
 | 311 | 
 | 
|---|
 | 312 | <pre>
 | 
|---|
 | 313 | 
 | 
|---|
 | 314 | sh_mtype modList[] = {
 | 
|---|
 | 315 | #ifdef SH_USE_UTMP
 | 
|---|
 | 316 |   {
 | 
|---|
 | 317 |     N_("UTMP"),
 | 
|---|
 | 318 |     0,
 | 
|---|
 | 319 |     sh_utmp_init,
 | 
|---|
 | 320 |     sh_utmp_timer,
 | 
|---|
 | 321 |     sh_utmp_check,
 | 
|---|
 | 322 |     sh_utmp_end,
 | 
|---|
 | 323 |     sh_utmp_null,
 | 
|---|
 | 324 | 
 | 
|---|
 | 325 |     N_("[Utmp]"),
 | 
|---|
 | 326 |     sh_utmp_table,
 | 
|---|
 | 327 |   },
 | 
|---|
 | 328 | #endif
 | 
|---|
 | 329 | </pre>
 | 
|---|
 | 330 | <p>
 | 
|---|
 | 331 | is the beginning of that table. The author of the sh_utmp module has
 | 
|---|
 | 332 | initialised the structure with the name of the module (note that N_()
 | 
|---|
 | 333 | is just a macro used to delimit strings here), a 0 to signify that the
 | 
|---|
 | 334 | module has not yet been initialised, and then pointers to _init(),
 | 
|---|
 | 335 | _timer(), _check(), _cleanup() and _reconf() functions for the
 | 
|---|
 | 336 | module. Finally, the last two structure elements are for configuration
 | 
|---|
 | 337 | file parsing: the first is the section heading in the configuration
 | 
|---|
 | 338 | file for this module, and the second is a table of type
 | 
|---|
 | 339 | </p>
 | 
|---|
 | 340 | 
 | 
|---|
 | 341 | <pre>
 | 
|---|
 | 342 | 
 | 
|---|
 | 343 | typedef struct rconf
 | 
|---|
 | 344 | {
 | 
|---|
 | 345 |   char * the_opt;
 | 
|---|
 | 346 |   int (*func)(char * opt);
 | 
|---|
 | 347 | } sh_rconf;
 | 
|---|
 | 348 | </pre>
 | 
|---|
 | 349 | 
 | 
|---|
 | 350 | <p>
 | 
|---|
 | 351 | (also defined in sh_modules.h). This structure is for storing options
 | 
|---|
 | 352 | for this module to be found in the configuration file, as well as the
 | 
|---|
 | 353 | functions that will be used to parse them when found. In the sh_utmp
 | 
|---|
 | 354 | example above, we can see that this table has been set to
 | 
|---|
 | 355 | sh_utmp_table - this is a reference to a list of the Utmp module's
 | 
|---|
 | 356 | configuration options declared in sh_utmp.h. It should be clear now
 | 
|---|
 | 357 | that one of the changes you will need to make to samhain's source
 | 
|---|
 | 358 | files is to include your header file in sh_modules.c and add a modList
 | 
|---|
 | 359 | entry like the above.
 | 
|---|
 | 360 | </p>
 | 
|---|
 | 361 | 
 | 
|---|
 | 362 | <p>
 | 
|---|
 | 363 | For a description of when during samhain's execution these various
 | 
|---|
 | 364 | module hooks are called, see the overview above. It would likely be
 | 
|---|
 | 365 | helpful to you now to read through the source for one of the modules
 | 
|---|
 | 366 | provided with samhain and see the above actually implemented. You
 | 
|---|
 | 367 | should also be able to use one of these modules as a template for your
 | 
|---|
 | 368 | own.
 | 
|---|
 | 369 | </p>
 | 
|---|
 | 370 | 
 | 
|---|
 | 371 | <h3>The message catalogue</h3>
 | 
|---|
 | 372 | 
 | 
|---|
 | 373 | <p>
 | 
|---|
 | 374 | Most module authors will want to log messages in their own specified
 | 
|---|
 | 375 | format; samhain stores all of its message formats in a "messages
 | 
|---|
 | 376 | catalogue" found in sh_cat.h and sh_cat.c. For example, for the
 | 
|---|
 | 377 | sh_suidchk module we find the following entries in sh_cat.h, as part
 | 
|---|
 | 378 | of an enum:
 | 
|---|
 | 379 | </p>
 | 
|---|
 | 380 | 
 | 
|---|
 | 381 | <pre>
 | 
|---|
 | 382 | 
 | 
|---|
 | 383 | #ifdef SH_USE_SUIDCHK
 | 
|---|
 | 384 |  MSG_SUID_POLICY,
 | 
|---|
 | 385 |  MSG_SUID_FOUND,
 | 
|---|
 | 386 |  MSG_SUID_STAT,
 | 
|---|
 | 387 |  MSG_SUID_SUMMARY,
 | 
|---|
 | 388 | #endif
 | 
|---|
 | 389 | </pre>
 | 
|---|
 | 390 | 
 | 
|---|
 | 391 | <p>
 | 
|---|
 | 392 | Correspondingly in sh_cat.c we find
 | 
|---|
 | 393 | </p>
 | 
|---|
 | 394 | 
 | 
|---|
 | 395 | <pre>
 | 
|---|
 | 396 | 
 | 
|---|
 | 397 | #ifdef SH_USE_SUIDCHK
 | 
|---|
 | 398 |   { MSG_SUID_POLICY, SH_ERR_SEVERE,  RUN,   N_("msg=\"POLICY SUIDCHK  %s\" path=\"%s\"") },
 | 
|---|
 | 399 |   { MSG_SUID_FOUND,  SH_ERR_INFO,    RUN,   N_("msg=\"Found suid/sgid file\" path=\"%s\"") },
 | 
|---|
 | 400 |   { MSG_SUID_STAT,   SH_ERR_ERR,     ERR,   N_("msg=\"stat: %s\" path=\"%s\"") },
 | 
|---|
 | 401 |   { MSG_SUID_SUMMARY,SH_ERR_INFO,    RUN,   N_("msg=\"Checked for SUID programs: %ld files, %ld seconds\"") },
 | 
|---|
 | 402 | #endif
 | 
|---|
 | 403 | </pre>
 | 
|---|
 | 404 | <p>
 | 
|---|
 | 405 | as part of the table msg_cat[] of type cat_entry:
 | 
|---|
 | 406 | </p>
 | 
|---|
 | 407 | <pre>
 | 
|---|
 | 408 | 
 | 
|---|
 | 409 | typedef struct foo_cat_entry {
 | 
|---|
 | 410 |   unsigned long id;
 | 
|---|
 | 411 |   unsigned long priority;
 | 
|---|
 | 412 |   unsigned long class;
 | 
|---|
 | 413 |   char *        format;
 | 
|---|
 | 414 | } cat_entry;
 | 
|---|
 | 415 | </pre>
 | 
|---|
 | 416 | <p>
 | 
|---|
 | 417 | The first member of this structure is the message type's ID, as
 | 
|---|
 | 418 | defined in the enum in sh_cat.h. The second is the default priority of
 | 
|---|
 | 419 | such messages, defined as in the samhain documentation. The third is
 | 
|---|
 | 420 | the class of the message, again defined as in the samhain
 | 
|---|
 | 421 | documentation. Finally we have the message format itself, which is a
 | 
|---|
 | 422 | printf() style format string.
 | 
|---|
 | 423 | </p>
 | 
|---|
 | 424 | <p>
 | 
|---|
 | 425 | This catalogue is used by the logging functions in samhain; you will
 | 
|---|
 | 426 | need to add your own message types and formats to sh_cat.h and
 | 
|---|
 | 427 | sh_cat.c. Note that because samhain can be compiled for XML style
 | 
|---|
 | 428 | logging, you will actually need to make two entries in sh_cat.c for
 | 
|---|
 | 429 | each message; see the file itself for details.
 | 
|---|
 | 430 | </p>
 | 
|---|
 | 431 | <p>
 | 
|---|
 | 432 | Note that there is a generic message format with the ID 'MSG_E_SUBGEN'
 | 
|---|
 | 433 | and the default priority 'SH_ERR_ERR'. If you are using this message
 | 
|---|
 | 434 | format, then you can log (a) a string, and (b) the name of the subroutine.
 | 
|---|
 | 435 | </p>
 | 
|---|
 | 436 | <p>
 | 
|---|
 | 437 | This completes our description of samhain's module interface.
 | 
|---|
 | 438 | </p>
 | 
|---|
 | 439 | 
 | 
|---|
 | 440 | <h2>Samhain's utility functions</h2>
 | 
|---|
 | 441 | <p>
 | 
|---|
 | 442 | Here we'll describe the main utility functions available to samhain module
 | 
|---|
 | 443 | authors.
 | 
|---|
 | 444 | </p>
 | 
|---|
 | 445 | 
 | 
|---|
 | 446 | <h3>String wrapping macros</h3>
 | 
|---|
 | 447 | 
 | 
|---|
 | 448 | <p>
 | 
|---|
 | 449 | Constant strings should be wrapped in the _(string) macro. Initialisation
 | 
|---|
 | 450 | strings that cannot be replaced with a function should be wrapped
 | 
|---|
 | 451 | in a N_(string) macro, and the variable thus initialized should be
 | 
|---|
 | 452 | wrapped in a _(var) macro whereever used. This is important for the
 | 
|---|
 | 453 | 'stealth' functionality of samhain.
 | 
|---|
 | 454 | </p>
 | 
|---|
 | 455 | 
 | 
|---|
 | 456 | <h3>Logging messages</h3>
 | 
|---|
 | 457 | 
 | 
|---|
 | 458 | <pre>
 | 
|---|
 | 459 | #include "sh_error.h"
 | 
|---|
 | 460 | 
 | 
|---|
 | 461 | void sh_error_handle(int severity, char * file, long line, long status,
 | 
|---|
 | 462 |                      unsigned long msg_id, ...)
 | 
|---|
 | 463 | </pre>
 | 
|---|
 | 464 | <p>
 | 
|---|
 | 465 | This is samhain's logging/reporting function, so the name is a little
 | 
|---|
 | 466 | misleading - errors are not the only thing we should handle with
 | 
|---|
 | 467 | this. The first four arguments are simple enough: severity is the
 | 
|---|
 | 468 | logging severity, defined in the enum ShErrLevel from sh_error.h; file
 | 
|---|
 | 469 | and line are the current file and line - usually you'll be using FIL__
 | 
|---|
 | 470 | and __LINE__ for these; status is not very important - for module
 | 
|---|
 | 471 | authors it'll do to always pass 0 to this. The final named argument is
 | 
|---|
 | 472 | msg_id, which should be one of the message IDs defined in sh_cat.h;
 | 
|---|
 | 473 | these correspond to message format strings in printf() format, which
 | 
|---|
 | 474 | will be interpolated with the following arguments to form the log
 | 
|---|
 | 475 | message.
 | 
|---|
 | 476 | </p>
 | 
|---|
 | 477 | <p>
 | 
|---|
 | 478 | The '__LINE__' macro is provided by the C preprocessor. The FIL__ macro
 | 
|---|
 | 479 | should be #defined to '_("sourcefile_name")' (see 'String wrapping macros'
 | 
|---|
 | 480 | above).
 | 
|---|
 | 481 | <p>
 | 
|---|
 | 482 | Example of use:
 | 
|---|
 | 483 | </p>
 | 
|---|
 | 484 | <pre>
 | 
|---|
 | 485 | #undef
 | 
|---|
 | 486 | #define FIL__ _("sh_mounts.c")
 | 
|---|
 | 487 | 
 | 
|---|
 | 488 | sh_error_handle(ShMountsSevMnt, FIL__, __LINE__, 0, MSG_MNT_MNTMISS,
 | 
|---|
 | 489 |                  cfgmnt->path);
 | 
|---|
 | 490 | </pre>
 | 
|---|
 | 491 | <p>
 | 
|---|
 | 492 | See cat.c for the definition of MSG_MNT_MNTMISS:
 | 
|---|
 | 493 | </p>
 | 
|---|
 | 494 | <pre>
 | 
|---|
 | 495 | 
 | 
|---|
 | 496 | { MSG_MNT_MNTMISS, SH_ERR_WARN,    RUN,   N_("msg=\"Mount missing\" path=\"%s\"")},
 | 
|---|
 | 497 | </pre>
 | 
|---|
 | 498 | <p>
 | 
|---|
 | 499 | So we print this out at severity ShMountsSevMnt, which in this case is
 | 
|---|
 | 500 | a configured value read from the samhain configuration file (see
 | 
|---|
 | 501 | sh_mounts.c). If we wanted to print it at the default severity
 | 
|---|
 | 502 | (SH_ERR_WARN), we could pass -1 as the severity.
 | 
|---|
 | 503 | </p>
 | 
|---|
 | 504 | 
 | 
|---|
 | 505 | <h3>Checking files for modification</h3>
 | 
|---|
 | 506 | 
 | 
|---|
 | 507 | <pre>
 | 
|---|
 | 508 | #include "sh_files.h"
 | 
|---|
 | 509 | 
 | 
|---|
 | 510 | int  sh_files_pushdir_?? (char * dirName);
 | 
|---|
 | 511 | int  sh_files_pushfile_?? (char * fileName);
 | 
|---|
 | 512 | </pre>
 | 
|---|
 | 513 | <p>
 | 
|---|
 | 514 | These functions push directories and files onto the stack of those to check 
 | 
|---|
 | 515 | for the specified policy (see the samhain documentation for further 
 | 
|---|
 | 516 | information):
 | 
|---|
 | 517 | <table>
 | 
|---|
 | 518 |         <tr><td> sh_files_pushdir_user0 </td><td>pushes the directory at USER0 </td></tr>
 | 
|---|
 | 519 |         <tr><td align=right> ... _user1</td><td align=right>USER1</td></tr>
 | 
|---|
 | 520 |         <tr><td align=right> ... _attr</td><td align=right>ATTR</td></tr>
 | 
|---|
 | 521 |         <tr><td align=right> ... _ro</td><td align=right>READONLY</td></tr>
 | 
|---|
 | 522 |         <tr><td align=right> ... _log</td><td align=right>LOGFILE</td></tr>
 | 
|---|
 | 523 |         <tr><td align=right> ... _glog</td><td align=right>GROWING LOGFILE</td></tr>
 | 
|---|
 | 524 |         <tr><td align=right> ... _noig</td><td align=right>IGNORE NONE</td></tr>
 | 
|---|
 | 525 |         <tr><td align=right> ... _allig</td><td align=right>IGNORE ALL</td></tr>
 | 
|---|
 | 526 | </table>
 | 
|---|
 | 527 | So if you're writing a module that adds particular files to check, like the 
 | 
|---|
 | 528 | sh_userfiles module for example, these are the functions to use.
 | 
|---|
 | 529 | </p>
 | 
|---|
 | 530 | 
 | 
|---|
 | 531 | <h3>Managing memory</h3>
 | 
|---|
 | 532 | 
 | 
|---|
 | 533 | <pre>
 | 
|---|
 | 534 | #include "sh_mem.h"
 | 
|---|
 | 535 | 
 | 
|---|
 | 536 | #define SH_FREE(a)  ...
 | 
|---|
 | 537 | #define SH_ALLOC(a) ...
 | 
|---|
 | 538 | </pre>
 | 
|---|
 | 539 | <p>
 | 
|---|
 | 540 | These are the macros to use when you're allocating/freeing memory in
 | 
|---|
 | 541 | samhain. They do all the error checking/reporting you need, so when
 | 
|---|
 | 542 | you get memory from SH_ALLOC you can just get to using it right away.
 | 
|---|
 | 543 | </p>
 | 
|---|
 | 544 | 
 | 
|---|
 | 545 | <h3>Parsing strings</h3>
 | 
|---|
 | 546 | 
 | 
|---|
 | 547 | <pre>
 | 
|---|
 | 548 | #include "sh_utils.h"
 | 
|---|
 | 549 | 
 | 
|---|
 | 550 | char * sh_util_strdup    (const char * str);
 | 
|---|
 | 551 | char * sh_util_strsep    (char **str, const char *delim);
 | 
|---|
 | 552 | char * sh_util_strconcat (const char * arg1, ...);
 | 
|---|
 | 553 | 
 | 
|---|
 | 554 | int sh_util_flagval(char * c, int * fval);
 | 
|---|
 | 555 | int sh_util_isnum (char *str);
 | 
|---|
 | 556 | 
 | 
|---|
 | 557 | #include "slib.h"
 | 
|---|
 | 558 | 
 | 
|---|
 | 559 | int sl_strlcpy (char * dst, const char * src, size_t siz);
 | 
|---|
 | 560 | int sl_strlcat (char * dst, const char * src, size_t siz);
 | 
|---|
 | 561 | int sl_snprintf(char *str, size_t n, const char *format, ... );
 | 
|---|
 | 562 | </pre>
 | 
|---|
 | 563 | <p>
 | 
|---|
 | 564 | These functions are the samhain internal functions for string
 | 
|---|
 | 565 | handling. The first three act like their C library counterparts,
 | 
|---|
 | 566 | except using samhain's memory management functions and error
 | 
|---|
 | 567 | checking. sh_util_flagval converts the passed string into a truth
 | 
|---|
 | 568 | value - the value is stored in <b>fval</b> as 1 or 0 - and returns 0
 | 
|---|
 | 569 | on success, -1 on failure. sh_util_isnum just checks if the passed
 | 
|---|
 | 570 | string is all numeric.
 | 
|---|
 | 571 | </p>
 | 
|---|
 | 572 | <p>
 | 
|---|
 | 573 | The functions sl_strlcpy and sl_strlcat work similar to the C library
 | 
|---|
 | 574 | strncpy/strncat functions, except that the destination string is always
 | 
|---|
 | 575 | null terminated, and the third argument must be the full length of the 
 | 
|---|
 | 576 | destination buffer, <i>not</i> the remaining space. On success, the 
 | 
|---|
 | 577 | return value is 0.
 | 
|---|
 | 578 | </p>
 | 
|---|
 | 579 | <p>
 | 
|---|
 | 580 | The function sl_snprintf provides either the system snprintf, or a replacement,
 | 
|---|
 | 581 | if the system has no or a buggy snprintf.
 | 
|---|
 | 582 | </p>
 | 
|---|
 | 583 | 
 | 
|---|
 | 584 | <h3>Tracing execution</h3>
 | 
|---|
 | 585 | 
 | 
|---|
 | 586 | <pre>
 | 
|---|
 | 587 | #include "slib.h"
 | 
|---|
 | 588 | 
 | 
|---|
 | 589 | #define SL_ENTER(s) ...
 | 
|---|
 | 590 | #define SL_RETURN(retval, s) ...
 | 
|---|
 | 591 | </pre>
 | 
|---|
 | 592 | <p>
 | 
|---|
 | 593 | These macros are for tracing execution through samhain functions. You
 | 
|---|
 | 594 | should use SL_ENTER with the name of the function for each function
 | 
|---|
 | 595 | entered, and SL_RETURN with the return value and the name of the
 | 
|---|
 | 596 | function for each exit if you want to maintain compatibility with the
 | 
|---|
 | 597 | rest of samhain.
 | 
|---|
 | 598 | </p>
 | 
|---|
 | 599 | 
 | 
|---|
 | 600 | <h3>Executing external programs (popen)</h3>
 | 
|---|
 | 601 | 
 | 
|---|
 | 602 | <pre>
 | 
|---|
 | 603 | #include "sh_extern.h"
 | 
|---|
 | 604 | 
 | 
|---|
 | 605 | 
 | 
|---|
 | 606 | sh_tas_t task;
 | 
|---|
 | 607 | /* Prepare task */
 | 
|---|
 | 608 | sh_ext_tas_init(&task);
 | 
|---|
 | 609 | sh_ext_tas_command(&task, char * command);
 | 
|---|
 | 610 | sh_ext_tas_add_argv(&task, char * val);
 | 
|---|
 | 611 | sh_ext_tas_add_envv (&task, char * environment_variable, char * value);
 | 
|---|
 | 612 | 
 | 
|---|
 | 613 | int sh_ext_popen(&task);
 | 
|---|
 | 614 | int sh_ext_pclose(&task);
 | 
|---|
 | 615 | </pre>
 | 
|---|
 | 616 | <p>
 | 
|---|
 | 617 | To prepare a task to run, use 'sh_ext_tas_init' to initialise the task
 | 
|---|
 | 618 | structure. With 'sh_ext_tas_command' the command (absolute path) is set,
 | 
|---|
 | 619 | with 'sh_ext_tas_add_argv' command line options are added. Environment
 | 
|---|
 | 620 | variables can be set with 'sh_ext_tas_add_envv'.
 | 
|---|
 | 621 | </p>
 | 
|---|
 | 622 | <p>
 | 
|---|
 | 623 | To open for read, set "task.rw = 'r';", to open for write
 | 
|---|
 | 624 | use "task.rw = 'w';".
 | 
|---|
 | 625 | </p>
 | 
|---|
 | 626 | <p>
 | 
|---|
 | 627 | To run the task with privileges dropped to another UID, set
 | 
|---|
 | 628 | "task.privileged = 0;" and task.run_user_uid, task.run_user_gid
 | 
|---|
 | 629 | to the desired UID/GID.
 | 
|---|
 | 630 | </p>
 | 
|---|
 | 631 | <p>
 | 
|---|
 | 632 | To verify the checksum of the called executable, set 
 | 
|---|
 | 633 | task.checksum[KEY_LEN+1] to the TIGER192 checksum of the executable.
 | 
|---|
 | 634 | </p>
 | 
|---|
 | 635 | <p>
 | 
|---|
 | 636 | After successful execution of sh_ext_popen (return status 0), 
 | 
|---|
 | 637 | task.pipe is the stream opened for read or write, and task.pipeFD
 | 
|---|
 | 638 | its associated file descriptor.
 | 
|---|
 | 639 | </p> 
 | 
|---|
 | 640 | 
 | 
|---|
 | 641 | <h3>Inserting arbitrary data into the baseline database</h3>
 | 
|---|
 | 642 | <pre>
 | 
|---|
 | 643 | 
 | 
|---|
 | 644 | #include "sh_hash.c"
 | 
|---|
 | 645 | 
 | 
|---|
 | 646 | void sh_hash_push2db (char * key, unsigned long val1, 
 | 
|---|
 | 647 |                       unsigned long val2, unsigned long val3,
 | 
|---|
 | 648 |                       unsigned char * str, int size);
 | 
|---|
 | 649 | 
 | 
|---|
 | 650 | char * sh_hash_db2pop (char * key, unsigned long * val1, 
 | 
|---|
 | 651 |                        unsigned long * val2, unsigned long * val3,
 | 
|---|
 | 652 |                        int * size);
 | 
|---|
 | 653 | </pre>
 | 
|---|
 | 654 | <p>
 | 
|---|
 | 655 | The baseline database has a fixed record format. To enter data, these need
 | 
|---|
 | 656 | to be prepared in the required format. To retrieve the data, the 
 | 
|---|
 | 657 | 'filepath' is used as key (if your data is not a file, you would provide
 | 
|---|
 | 658 | a dummy pathname as key). For convenience, the two functions noted below
 | 
|---|
 | 659 | are provided.
 | 
|---|
 | 660 | </p>
 | 
|---|
 | 661 | <p>
 | 
|---|
 | 662 | When checking files, samhain will walk the database to find files that
 | 
|---|
 | 663 | are in the database, but have been deleted from the disk. If you enter
 | 
|---|
| [161] | 664 | data, you need to mark it as such by using a key that
 | 
|---|
 | 665 | starts with something else but '/', otherwise samhain will complain
 | 
|---|
 | 666 | if it has not been checked during the file check.
 | 
|---|
| [1] | 667 | </p>
 | 
|---|
 | 668 | <pre>
 | 
|---|
 | 669 | 
 | 
|---|
 | 670 | #include "sh_hash.c"
 | 
|---|
 | 671 | 
 | 
|---|
 | 672 | void sh_hash_push2db (char * key, unsigned long val1, 
 | 
|---|
 | 673 |                       unsigned long val2, unsigned long val3,
 | 
|---|
 | 674 |                       unsigned char * str, int size);
 | 
|---|
 | 675 | 
 | 
|---|
 | 676 | char * sh_hash_db2pop (char * key, unsigned long * val1, 
 | 
|---|
 | 677 |                        unsigned long * val2, unsigned long * val3,
 | 
|---|
 | 678 |                        int * size);
 | 
|---|
 | 679 | </pre>
 | 
|---|
 | 680 | <p>
 | 
|---|
 | 681 | To insert data, use 'sh_hash_push2db'. You can insert up to three long
 | 
|---|
 | 682 | integers (val1, val2, val3) and/or a binary string of length size 
 | 
|---|
 | 683 | (max. (PATH_MAX-1)/2). As noted
 | 
|---|
 | 684 | above, you need to supply a key (stored as the 'filepath', which should
 | 
|---|
| [161] | 685 | start with a character different from '/'). To retrieve data, you can use
 | 
|---|
| [1] | 686 | 'sh_hash_db2pop'. The return value is either NULL (if no string was
 | 
|---|
 | 687 | stored under this key), or the stored string (length returned in 'size').
 | 
|---|
 | 688 | </p>
 | 
|---|
 | 689 | <p>
 | 
|---|
 | 690 | A string to store may consist of any characters, including NULLs, and
 | 
|---|
 | 691 | need not be NULL terminated. The returned string is
 | 
|---|
 | 692 | always NULL terminated (the terminating NULL is not included in 'size'), 
 | 
|---|
 | 693 | and should be freed with SH_FREE() if not required anymore.
 | 
|---|
 | 694 | </p>
 | 
|---|
 | 695 | <p>
 | 
|---|
 | 696 | If the key is not found in the database, <b>size</b> is set to -1.
 | 
|---|
 | 697 | </p>
 | 
|---|
 | 698 | 
 | 
|---|
 | 699 | <h2>Incorporating modules into the samhain build</h2>
 | 
|---|
 | 700 | <p>
 | 
|---|
 | 701 | This is a somewhat secondary but important part of writing a module 
 | 
|---|
 | 702 | for samhain:
 | 
|---|
 | 703 | how to incorporate it into the samhain configuration and build process. 
 | 
|---|
 | 704 | This just involves hacking the autoconf and makefile setup to include your 
 | 
|---|
 | 705 | module. We'll present this file-by-file.
 | 
|---|
 | 706 | </p>
 | 
|---|
 | 707 | <h3>Makefile.in</h3>
 | 
|---|
 | 708 | <p>
 | 
|---|
 | 709 | You need to add a few bits to this file. First, add your header,
 | 
|---|
 | 710 | source and object filenames to the HEADERS, SOURCES and OBJECTS
 | 
|---|
 | 711 | variables. Then add your header to the dependencies for sh_modules.o
 | 
|---|
 | 712 | and ./sh_modules.o. Finally add dependency lines for your module
 | 
|---|
 | 713 | object file sh_whatever.o and ./sh_whatever.o, modelling them on the
 | 
|---|
 | 714 | other module object dependency lines.
 | 
|---|
 | 715 | </p>
 | 
|---|
 | 716 | <h3>acconfig.h</h3>
 | 
|---|
 | 717 | <p>
 | 
|---|
 | 718 | The config.h.in will be generated from this file by 'autoheader'. 
 | 
|---|
 | 719 | You just need to add a line like
 | 
|---|
 | 720 | <pre>
 | 
|---|
 | 721 | #undef SH_USE_MOUNTS
 | 
|---|
 | 722 | </pre>
 | 
|---|
 | 723 | that will be defined by the ./configure code if the user specifies 
 | 
|---|
 | 724 | the module as enabled.
 | 
|---|
 | 725 | </p>
 | 
|---|
 | 726 | <h3>aclocal.m4</h3>
 | 
|---|
 | 727 | <p>
 | 
|---|
 | 728 | This file is used by 'autoconf' to help generate ./configure. You need to add 
 | 
|---|
 | 729 | your module's ./configure option to the SH_ENABLE_OPTS variable; for example,
 | 
|---|
 | 730 | to add the option --enable-mounts-check, we added the string 'mounts-check' to
 | 
|---|
 | 731 | this variable.
 | 
|---|
 | 732 | </p>
 | 
|---|
 | 733 | <h3>configure.ac</h3>
 | 
|---|
 | 734 | This is the other file used by 'autoconf' to generate ./configure. You need to
 | 
|---|
 | 735 | add an AC_ARG_ENABLE call to this file, along the lines of those for other
 | 
|---|
 | 736 | modules. For example, we added
 | 
|---|
 | 737 | <pre>
 | 
|---|
 | 738 | AC_ARG_ENABLE(mounts-check,
 | 
|---|
 | 739 |         [  --enable-mounts-check        check mount options on filesystems [[no]
 | 
|---|
 | 740 | ]],
 | 
|---|
 | 741 |         [
 | 
|---|
 | 742 |         if test "x${enable_mounts_check}" = xyes; then
 | 
|---|
 | 743 |                 AC_DEFINE(SH_USE_MOUNTS)
 | 
|---|
 | 744 |         fi
 | 
|---|
 | 745 |         ]
 | 
|---|
 | 746 | )
 | 
|---|
 | 747 | </pre>
 | 
|---|
 | 748 | for the sh_mounts module. This causes the #undef from acconfig.h above 
 | 
|---|
 | 749 | to be defined when ./configure is run with the --enable-mounts-check argument.
 | 
|---|
 | 750 | </p>
 | 
|---|
 | 751 | This is all that you need. Once you've done the above, you'll need to
 | 
|---|
 | 752 | run 'autoheader' and 'autoconfig' to generate config.h.in and the 
 | 
|---|
 | 753 | ./configure script. Then your module will build as part of the samhain
 | 
|---|
 | 754 | source.
 | 
|---|
 | 755 | </p>
 | 
|---|
 | 756 | 
 | 
|---|
 | 757 | <h2>Conclusion</h2>
 | 
|---|
 | 758 | <p>
 | 
|---|
 | 759 | Armed with the above information, any proficient C programmer should
 | 
|---|
 | 760 | be able to adapt and extend samhain to do whatever it is they need. We
 | 
|---|
 | 761 | hope that this document has been reasonably clear, easy to follow and
 | 
|---|
 | 762 | useful; please feel free to update it for clarity, accuracy and
 | 
|---|
 | 763 | completeness and resubmit it to the samhain project.
 | 
|---|
 | 764 | </p>
 | 
|---|
 | 765 | <p>
 | 
|---|
 | 766 | This document was written by the eircom.net Computer Incident Response Team.
 | 
|---|
 | 767 | Updated with CSS by Rainer Wichmann.
 | 
|---|
 | 768 | </p>
 | 
|---|
 | 769 | </div>
 | 
|---|
 | 770 | </body>
 | 
|---|
 | 771 | </html>
 | 
|---|